[
  {
    "path": ".gitignore",
    "content": "# 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# Eclipse\n.settings/\n.project\n\n# OSX\n.DS_Store\n/.nb-gradle/private/"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nCopyright (c) 2014 techdev Solutions UG http://techdev.de\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "trackr backend\n==============\n\nWhat is it?\n-------------\ntrackr is an application to track petty much everything that is going on in your company.\nKeep track of vacations, sick days, invoices and many more.\n\ntrackr 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\nbackend, a stateless REST API with either OAuth2 or basic authentication.\n\nYou can read all about trackr in our developer blog:\n\n* [Architecture and Backend](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-i/)\n* [Testing](http://blog.techdev.de/testing-a-secured-spring-data-rest-service-with-java-8-and-mockmvc/)\n* [Mail Approvals with Spring Integration](http://blog.techdev.de/mail-approvals-with-spring-integration/)\n* [Frontend](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-ii/)\n* [File Downloads with AngularJS](http://blog.techdev.de/an-angularjs-directive-to-download-pdf-files/)\n* [Processes and Tools](http://blog.techdev.de/trackr-an-angularjs-app-with-a-java-8-backend-part-iii/)\n\nFor the API documentation just go [here](http://techdev-solutions.github.io/trackr-api-documentation/getting_started.html).\nThere is also a [Vagrant](https://www.vagrantup.com/) project building the whole application over [here](https://github.com/techdev-solutions/trackr-vagrant).\n\nHow to start\n------------\nIf 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).\n\nIf you have gradle, just run\n\n    gradle run\n\nIf you don't have gradle and want to use the wrapper run\n\n    ./gradlew run\n    # or\n    gradlew.bat run\n\nIf you want to start from your IDE, i.e. for debugging open the class `Trackr` and start the main method.\n\nTo 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\nchange them in import.sql.\n\n    curl --user moritz.schulze@techdev.de localhost:8080\n\nThe default config uses port 8080, if that is used on your system you can add\n\n    server:\n        port: $port\n\nto the top of the application.yaml and choose a port that you want for `$port`.\n\nProfiles\n--------\ntrackr has a lot of Spring profiles to add/switch features.\n\n| profile            | description                                                | notes                                                            |\n|--------------------|------------------------------------------------------------|------------------------------------------------------------------|\n| in-memory-database | uses a H2 database, creates the schema with hibernate      | excluse with real-database                                       |\n| real-database      | uses a configurable database, executes flyway              | exclusive with in-memory-database                                |\n| http-basic         | protects the API with HTTP basic authentication            | exclusive with oauth                                             |\n| oauth              | protects the API as a OAuth2 resource server               | exclusive with http-basic. Database for OAuth2 tokens needed.    |\n| granular-security  | roles and per endpoint security                            |                                                                  |\n| gmail              | sends mail with Gmail and enables mail receiving           | when off, does not receive mails and uses a logging mail sender. |\n| dev                | initialize the database with data.sql                      |                                                                  |\n| prod               | Just some different settings for our production env        |                                                                  |\n\nTake a look in the application.yaml to see what properties these profiles need.\n\nThe default profiles are `in-memory-database,dev,granular-security,http-basic`. If you want to use other profiles, there are several possible ways.\n1. You can change the `spring.profiles.active` value in application.yaml\n2. 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`.\n3. If you run from your IDE, you can add `--spring.profiles.active=dev,gmail,real-database` as program arguments to the run configuration.\n\nPlease refer to the [Spring Boot Reference](http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/) for more information.\n\n### The oauth profile\nThe 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\nJDBC 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.\n\n\n### The granular-security profile\nWhen 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\nid of the user. In trackr, the id of a user is the email address of the belonging employee.\n\nWhen 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.\n\nTake a look at the `@PreAuthorize` and `@PostAuthorize` annotations in the code to see what this will activate.\n\nHow to build\n------------\nJust run\n\n    gradle build\n\n(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\nworking directory where the `java` command was issued."
  },
  {
    "path": "application.yaml",
    "content": "spring:\n    jpa:\n        hibernate:\n            naming:\n                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl\n                implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl\n    datasource:\n        initialize: false\n    profiles:\n        active: in-memory-database,dev,granular-security,http-basic\ntrackr:\n    frontendUrl: http://localhost\nlogging:\n    config: classpath:logback-console.xml\n\n---\nspring:\n    profiles: prod\ntrackr:\n    frontendUrl:\nlogging:\n    config: classpath:logback-file.xml\n\n---\nspring:\n    profiles: dev\n    datasource:\n        initialize: true\n\n---\nspring:\n    profiles: real-database\n    jpa:\n        hibernate:\n            dialect: org.hibernate.dialect.PostgreSQLDialect\n            ddl-auto: validate\n    datasource:\n        driverClassName: org.postgresql.Driver\n        url: jdbc:postgresql://127.0.0.1:5432/trackr\n        username:\n        password:\nflyway:\n    schemas: public\n\n---\nspring:\n    profiles: in-memory-database\n    datasource:\n        driverClassName: org.h2.Driver\n        url: jdbc:h2:mem:trackr;DB_CLOSE_DELAY\\=-1\n        username: sa\n        password:\n    jpa:\n        hibernate:\n            dialect: org.hibernate.dialect.H2Dialect\n            ddl-auto: create\nflyway:\n    enabled: false\n\n---\nspring:\n    profiles: oauth\ntrackr:\n    database:\n        oauth:\n            driverClassName: org.postgresql.Driver\n            url: jdbc:postgresql://127.0.0.1:5432/techdev_oauth\n            username:\n            password:\n\n---\nspring:\n    profiles: gmail\n    mail:\n        host: smtp.gmail.com\n        port: 465\n        username:\n        password:\n        properties:\n            mail.smtp.auth: true\n            mail.smtp.starttls.enable: true\n            mail.transport.protocol: smtp\n            mail.smtp.socketFactory.class: javax.net.ssl.SSLSocketFactory"
  },
  {
    "path": "build.gradle",
    "content": "plugins {\n    id 'org.springframework.boot' version '1.5.19.RELEASE'\n}\n\napply plugin: 'java'\napply plugin: 'jacoco'\n\nsourceCompatibility = 1.8\ncompileJava.options.encoding = 'UTF-8'\n\n// Options for naming the JAR file\narchivesBaseName = 'trackr-backend'\nversion = '1.0'\nif(project.hasProperty('teamcity')) {\n    version += '-build-' + project.teamcity['build.number']\n} else {\n    version += '-localbuild'\n}\n\nrepositories {\n    mavenCentral()\n}\n\nspringBoot {\n    executable = true\n}\n\ndependencies {\n    compile \"org.springframework.boot:spring-boot-starter-data-rest\"\n    compile \"org.springframework.boot:spring-boot-starter-data-jpa\"\n    compile \"org.springframework.boot:spring-boot-starter-mail\"\n    compile \"org.springframework.boot:spring-boot-starter-integration\"\n    compile \"org.springframework.boot:spring-boot-starter-security\"\n\n    // not included in boot\n    compile \"org.springframework.integration:spring-integration-mail:4.2.5.RELEASE\"\n    compile \"org.springframework.security.oauth:spring-security-oauth2\"\n\n    compile \"com.h2database:h2\"\n    compile \"org.postgresql:postgresql\"\n    compile \"org.flywaydb:flyway-core\"\n\n    compile(\"org.xhtmlrenderer:flying-saucer-pdf-itext5:9.0.6\")\n    compile(\"org.thymeleaf:thymeleaf\")\n\n    compileOnly \"org.projectlombok:lombok:1.12.4\"\n    testCompileOnly \"org.projectlombok:lombok:1.12.4\"\n    annotationProcessor \"org.projectlombok:lombok:1.12.4\"\n    testAnnotationProcessor \"org.projectlombok:lombok:1.12.4\"\n\n    compile \"org.glassfish:javax.json:1.0\"\n\n    // Not included by default for Spring Boot 1.5\n    compile \"commons-io:commons-io:2.1\"\n\n    testCompile \"org.springframework.boot:spring-boot-starter-test\"\n    testCompile(\"org.echocat.jomon:testing:1.4.3\") {\n        exclude group: \"org.mockito\"\n    }\n    testCompile \"org.mockito:mockito-core:1.9.5\"\n    testCompile \"com.jayway.jsonpath:json-path\"\n    testCompile \"org.apache.httpcomponents:httpclient\"\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Fri Jan 23 09:44:57 CET 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.2-bin.zip\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched.\nif $cygwin ; then\n    [ -n \"$JAVA_HOME\" ] && JAVA_HOME=`cygpath --unix \"$JAVA_HOME\"`\nfi\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >&-\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >&-\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/Trackr.java",
    "content": "package de.techdev.trackr;\n\nimport org.springframework.boot.ApplicationPid;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;\nimport org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ImportResource;\nimport org.springframework.context.annotation.Primary;\n\nimport java.io.File;\nimport java.io.IOException;\nimport javax.annotation.PostConstruct;\nimport javax.sql.DataSource;\n\n@SpringBootApplication(exclude = MailSenderAutoConfiguration.class)\n@ImportResource(value = \"classpath:META-INF/mail-integration.xml\")\npublic class Trackr {\n\n    @Bean\n    @Primary\n    @ConfigurationProperties(\"spring.datasource\")\n    public DataSource primaryDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @PostConstruct\n    private void handlePid() throws IOException {\n        File file = new File(\"application.pid\");\n        new ApplicationPid().write(file);\n        file.deleteOnExit();\n    }\n\n    public static void main(String[] args) {\n        SpringApplication.run(Trackr.class, args);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/mail/GMailConfiguration.java",
    "content": "package de.techdev.trackr.core.mail;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.mail.MailProperties;\nimport org.springframework.boot.context.properties.EnableConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.mail.javamail.JavaMailSenderImpl;\n\nimport java.util.Map;\nimport java.util.Properties;\nimport javax.mail.Session;\n\n/**\n * This configuration class is mostly copied from {@link org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration}.\n *\n * Since we need to expose the {@link #mailSession()} for our {@code mail-integration.xml} to work and the Spring autoconfig\n * class creates a circular dependency (JavaMailSender <-> Session) we have to use the relevant parts ourselves.\n */\n@Configuration\n@EnableConfigurationProperties(MailProperties.class)\n@Profile(\"gmail\")\npublic class GMailConfiguration {\n\n    @Autowired\n    private MailProperties properties;\n\n    @Bean\n    public JavaMailSenderImpl mailSender() {\n        JavaMailSenderImpl sender = new JavaMailSenderImpl();\n        applyProperties(sender);\n        return sender;\n    }\n\n    private void applyProperties(JavaMailSenderImpl sender) {\n        sender.setHost(this.properties.getHost());\n        if (this.properties.getPort() != null) {\n            sender.setPort(this.properties.getPort());\n        }\n        sender.setUsername(this.properties.getUsername());\n        sender.setPassword(this.properties.getPassword());\n        sender.setProtocol(this.properties.getProtocol());\n        if (this.properties.getDefaultEncoding() != null) {\n            sender.setDefaultEncoding(this.properties.getDefaultEncoding().name());\n        }\n        if (!this.properties.getProperties().isEmpty()) {\n            sender.setJavaMailProperties(asProperties(this.properties.getProperties()));\n        }\n    }\n\n    private Properties asProperties(Map<String, String> source) {\n        Properties properties = new Properties();\n        properties.putAll(source);\n        return properties;\n    }\n\n    /**\n     * We expose the mail session as a bean for the Spring Integration mail receiver.\n     */\n    @Bean\n    public Session mailSession() {\n        return mailSender().getSession();\n    }\n\n}"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/mail/MailService.java",
    "content": "package de.techdev.trackr.core.mail;\n\nimport org.springframework.mail.SimpleMailMessage;\n\n/**\n * @author Moritz Schulze\n */\npublic interface MailService {\n\n    void sendMail(SimpleMailMessage mailMessage);\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/mail/support/AsyncMailService.java",
    "content": "package de.techdev.trackr.core.mail.support;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.mail.MailMessage;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.messaging.Message;\nimport org.springframework.messaging.MessageChannel;\nimport org.springframework.messaging.support.GenericMessage;\nimport org.springframework.stereotype.Component;\n\n/**\n * Puts the mail message into a queue to be sent by Spring Integration.\n */\n@Component\npublic class AsyncMailService implements MailService {\n\n    @Autowired\n    @Qualifier(\"mailSendChannel\")\n    private MessageChannel mailChannel;\n\n    @Override\n    public void sendMail(SimpleMailMessage mailMessage) {\n        Message<MailMessage> asyncMessage = new GenericMessage<>(mailMessage);\n        mailChannel.send(asyncMessage);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/mail/support/NoOpJavaMailSender.java",
    "content": "package de.techdev.trackr.core.mail.support;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.MimeMessagePreparator;\nimport org.springframework.stereotype.Component;\n\nimport javax.mail.internet.MimeMessage;\nimport java.io.InputStream;\nimport java.util.Arrays;\n\n@Slf4j\n@Profile(\"!gmail\")\n@Component(\"mailSender\")\npublic class NoOpJavaMailSender implements JavaMailSender {\n\n    @Override\n    public MimeMessage createMimeMessage() {\n        log.debug(\"Create mime message\");\n        return null;\n    }\n\n    @Override\n    public MimeMessage createMimeMessage(InputStream contentStream) {\n        log.debug(\"Create Mime message with stream\");\n        return null;\n    }\n\n    @Override\n    public void send(MimeMessage mimeMessage) {\n        log.debug(\"Send single mime message\");\n    }\n\n    @Override\n    public void send(MimeMessage[] mimeMessages) {\n        log.debug(\"Send multiple mime messages\");\n    }\n\n    @Override\n    public void send(MimeMessagePreparator mimeMessagePreparator) {\n        log.debug(\"Send mime message preparator\");\n    }\n\n    @Override\n    public void send(MimeMessagePreparator[] mimeMessagePreparators) {\n        log.debug(\"Send multiple mime message preparators\");\n    }\n\n    @Override\n    public void send(SimpleMailMessage simpleMessage) {\n        StringBuilder builder = new StringBuilder(\"Send simple mail message..\\n\");\n        builder\n                .append(\"From:    \").append(simpleMessage.getFrom()).append(\"\\n\")\n                .append(\"To:      \").append(Arrays.toString(simpleMessage.getTo())).append(\"\\n\")\n                .append(\"Subject: \").append(simpleMessage.getSubject()).append(\"\\n\")\n                .append(\"--------------------------------------------\").append(\"\\n\")\n                .append(simpleMessage.getText());\n\n        log.debug(builder.toString());\n    }\n\n    @Override\n    public void send(SimpleMailMessage[] simpleMessages) {\n        log.debug(\"Send multiple simple messages\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/pdf/HtmlPdfConverter.java",
    "content": "package de.techdev.trackr.core.pdf;\n\nimport com.itextpdf.text.DocumentException;\nimport org.xhtmlrenderer.pdf.ITextRenderer;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\n/**\n * @author Moritz Schulze\n */\npublic class HtmlPdfConverter {\n\n    private ITextRenderer renderer;\n\n    public HtmlPdfConverter() {\n        renderer = new ITextRenderer();\n\n        //This can be used to set a font?\n//        ITextFontResolver fontResolver = renderer.getFontResolver();\n//        ClassPathResource regular = new ClassPathResource(\"/META-INF/fonts/LiberationSerif-Regular.ttf\");\n//        fontResolver.addFont(regular.getURL().toString(), BaseFont.IDENTITY_H, true);\n    }\n\n    public byte[] renderHtmlToPdf(String htmlContent) throws PdfCreationException {\n        renderer.setDocumentFromString(htmlContent);\n        renderer.layout();\n        byte[] pdfAsByteArray;\n        try(ByteArrayOutputStream bos = new ByteArrayOutputStream()) {\n            renderer.createPDF(bos);\n            pdfAsByteArray = bos.toByteArray();\n        } catch (DocumentException | IOException e) {\n            throw new PdfCreationException(e);\n        }\n        return pdfAsByteArray;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/pdf/PdfCreationException.java",
    "content": "package de.techdev.trackr.core.pdf;\n\n/**\n * @author Moritz Schulze\n */\npublic class PdfCreationException extends Exception {\n    public PdfCreationException(Exception e) {\n        super(e);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/pdf/PdfRenderer.java",
    "content": "package de.techdev.trackr.core.pdf;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.thymeleaf.context.Context;\n\nimport javax.annotation.PostConstruct;\n\n/**\n * @author Moritz Schulze\n */\n@Slf4j\npublic class PdfRenderer {\n\n//    @Value(\"${pdf.templatePath:META-INF/pdfTemplates}\")\n    @Value(\"pdfTemplates/\")\n    private String templatePath;\n\n//    @Value(\"${pdf.templateSuffix:pdf.templateSuffix:.html}\")\n    @Value(\".html\")\n    private String templateSuffix;\n\n    private ThymeleafRenderer thymeleafRenderer;\n    private HtmlPdfConverter htmlPdfConverter;\n\n    public PdfRenderer() {\n        htmlPdfConverter = new HtmlPdfConverter();\n    }\n\n    @PostConstruct\n    public void setUpRenderer() {\n        thymeleafRenderer = new ThymeleafRenderer(templatePath, templateSuffix);\n    }\n\n    public byte[] renderPdf(String templateName, Context context) throws PdfCreationException {\n        log.debug(\"Rendering template {}\", templateName);\n        String htmlContent = thymeleafRenderer.renderTemplateToHtml(templateName, context);\n        return htmlPdfConverter.renderHtmlToPdf(htmlContent);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/pdf/ThymeleafRenderer.java",
    "content": "package de.techdev.trackr.core.pdf;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.thymeleaf.TemplateEngine;\nimport org.thymeleaf.context.Context;\nimport org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;\n\n/**\n * Renders a thymeleaf template as a String containing HTML.\n *\n * @author Moritz Schulze\n */\n@Slf4j\npublic class ThymeleafRenderer {\n\n    private TemplateEngine templateEngine;\n\n    private String templatePath;\n\n    private String templateSuffix;\n\n    public ThymeleafRenderer(String templatePath, String templateSuffix) {\n        this.templatePath = templatePath;\n        this.templateSuffix = templateSuffix;\n        setUpTemplateEngine();\n    }\n\n    private void setUpTemplateEngine() {\n        ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();\n        log.debug(\"Configuring template resolver with: path {}, suffix {}\", templatePath, templateSuffix);\n        templateResolver.setPrefix(templatePath);\n        templateResolver.setSuffix(templateSuffix);\n        templateResolver.setTemplateMode(\"XHTML\");\n        templateResolver.setCharacterEncoding(\"UTF-8\");\n\n        this.templateEngine = new TemplateEngine();\n        this.templateEngine.setTemplateResolver(templateResolver);\n    }\n\n    /**\n     * Render the given template to HTML with the context.\n     *\n     * @param templateName The template to render.\n     * @param context      The context to use when rendering the template.\n     * @return The HTML content of the rendered template as a String.\n     */\n    public String renderTemplateToHtml(String templateName, Context context) {\n        return templateEngine.process(templateName, context);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/AuthorityService.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport java.util.Collection;\n\n/**\n * Access GrantedAuthorities for Employees and emails by GrantedAuthorities\n */\npublic interface AuthorityService {\n\n    /**\n     * Get all email addresses from employees who have the given authority.\n     */\n    Collection<String> getEmployeeEmailsByAuthority(String authority);\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/InMemoryAuthorityService.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.stereotype.Service;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\n\n@Service\n@Profile(\"!oauth\")\npublic class InMemoryAuthorityService implements AuthorityService {\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Override\n    public Collection<String> getEmployeeEmailsByAuthority(String authority) {\n        return employeeRepository.findAllForAddressBook(new PageRequest(0, 100)).getContent().stream().map(Employee::getEmail).collect(Collectors.toList());\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/InMemorySecurityConfiguration.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.security.authentication.BadCredentialsException;\nimport org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.User;\n\nimport static java.util.Arrays.asList;\n\n/**\n * This configuration enables HTTP Basic authentication and uses the employees as credentials, all with no password and admin access.\n *\n * It is only enabled when the oauth profile is off.\n */\n@EnableWebSecurity\n@Configuration\n@Profile(\"http-basic\")\npublic class InMemorySecurityConfiguration extends WebSecurityConfigurerAdapter {\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Override\n    protected void configure(AuthenticationManagerBuilder auth) throws Exception {\n        auth\n            .userDetailsService(username -> {\n                        Employee employee = employeeRepository.findByEmail(username);\n                        if (employee == null) {\n                            throw new BadCredentialsException(\"User not found\");\n                        }\n                        return new User(username, \"\", asList(new SimpleGrantedAuthority(\"ROLE_ADMIN\")));\n                    }\n            );\n    }\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.\n                authorizeRequests().anyRequest().fullyAuthenticated()\n                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)\n            .and()\n                .httpBasic()\n                .realmName(\"trackr development realm\")\n            .and()\n                .csrf().disable();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/MethodSecurityConfiguration.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;\nimport org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;\nimport org.springframework.security.access.hierarchicalroles.RoleHierarchy;\nimport org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;\nimport org.springframework.security.access.vote.RoleHierarchyVoter;\nimport org.springframework.security.access.vote.RoleVoter;\nimport org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;\nimport org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;\n\n/**\n * This class enables global method security via {@link org.springframework.security.access.prepost.PreAuthorize} in JPA Repositories\n * and other controllers. It also enables the role hierarchy in them.\n */\n@Profile(\"granular-security\")\n@Configuration\n@EnableGlobalMethodSecurity(prePostEnabled = true)\npublic class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {\n\n    @Autowired\n    private ApplicationContext applicationContext;\n\n    /**\n     * This is needed so {@link org.springframework.security.access.prepost.PreAuthorize} and so on know the role hierarchy.\n     */\n    @Override\n    protected MethodSecurityExpressionHandler createExpressionHandler() {\n        DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler = new DefaultMethodSecurityExpressionHandler();\n        methodSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());\n\n        //Needs to be done so we can access beans in security expressions\n        methodSecurityExpressionHandler.setApplicationContext(applicationContext);\n        return methodSecurityExpressionHandler;\n    }\n\n    @Bean\n    public RoleHierarchy roleHierarchy() {\n        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();\n        //TODO make this configurable\n        roleHierarchy.setHierarchy(\"ROLE_ADMIN > ROLE_SUPERVISOR ROLE_SUPERVISOR > ROLE_EMPLOYEE ROLE_EMPLOYEE > ROLE_ANONYMOUS\");\n        return roleHierarchy;\n    }\n    @Bean\n    public RoleVoter roleVoter() {\n        return new RoleHierarchyVoter(roleHierarchy());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/OAuth2AuthorityService.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.jdbc.core.JdbcTemplate;\nimport org.springframework.stereotype.Service;\n\nimport javax.sql.DataSource;\nimport java.util.Collection;\n\n@Service\n@Profile(\"oauth\")\npublic class OAuth2AuthorityService implements AuthorityService {\n\n    private JdbcTemplate jdbcTemplate;\n\n    @Autowired\n    public OAuth2AuthorityService(@Qualifier(\"oauthDataSource\") DataSource dataSource) {\n        jdbcTemplate = new JdbcTemplate(dataSource);\n    }\n\n    @Override\n    public Collection<String> getEmployeeEmailsByAuthority(String authority) {\n        return jdbcTemplate.queryForList(\"SELECT username FROM authorities WHERE authority = ?\", String.class, authority);\n    }\n\n}"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/security/OAuth2ResourceServerConfiguration.java",
    "content": "package de.techdev.trackr.core.security;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.security.config.annotation.web.builders.HttpSecurity;\nimport org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;\nimport org.springframework.security.config.http.SessionCreationPolicy;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;\nimport org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;\nimport org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;\nimport org.springframework.security.oauth2.provider.token.TokenStore;\nimport org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;\n\nimport javax.sql.DataSource;\nimport java.util.Collections;\n\n@Profile(\"oauth\")\n@EnableWebSecurity\n@Configuration\n@EnableResourceServer\npublic class OAuth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter {\n\n    private static final String TRACKR_RESOURCE_ID = \"techdev-services\";\n\n    @Bean\n    @Qualifier(\"oauthDataSource\")\n    @ConfigurationProperties(prefix = \"trackr.database.oauth\")\n    public DataSource oauthDataSource() {\n        return DataSourceBuilder.create().build();\n    }\n\n    @Bean\n    public TokenStore tokenStore() {\n        return new JdbcTokenStore(oauthDataSource());\n    }\n\n\n    @Override\n    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {\n        resources.resourceId(TRACKR_RESOURCE_ID).tokenStore(tokenStore());\n    }\n\n    @Override\n    public void configure(HttpSecurity http) throws Exception {\n        User anonymousUser =\n                new User(\"anonymous\", \"EMPTY\", Collections.singletonList(new SimpleGrantedAuthority(\"ROLE_ANONYMOUS\")));\n\n        http\n                .anonymous()\n                .principal(anonymousUser)\n                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // since this is just a REST API we don't need a state.\n                .and().requestMatchers().antMatchers(\"/**\")\n                .and().authorizeRequests()\n                .antMatchers(HttpMethod.OPTIONS, \"/**\").permitAll()\n                .antMatchers(HttpMethod.GET, \"/**\").access(\"#oauth2.hasScope('read')\")\n                .antMatchers(HttpMethod.PATCH, \"/**\").access(\"#oauth2.hasScope('write')\")\n                .antMatchers(HttpMethod.POST, \"/**\").access(\"#oauth2.hasScope('write')\")\n                .antMatchers(HttpMethod.PUT, \"/**\").access(\"#oauth2.hasScope('write')\")\n                .antMatchers(HttpMethod.DELETE, \"/**\").access(\"#oauth2.hasScope('write')\");\n\n        http.headers().addHeaderWriter((request, response) -> {\n            response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n            response.setHeader(\"Access-Control-Allow-Methods\", \"POST, GET, OPTIONS, DELETE\");\n            response.setHeader(\"Access-Control-Max-Age\", \"3600\");\n            if (request.getMethod().equals(\"OPTIONS\")) {\n                response.setHeader(\"Access-Control-Allow-Headers\", request.getHeader(\"Access-Control-Request-Headers\"));\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/ApiRepositoryRestConfiguration.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport de.techdev.trackr.core.web.converters.DateConverter;\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.domain.company.ContactPerson;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.expenses.TravelExpense;\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport de.techdev.trackr.domain.employee.expenses.reports.comments.Comment;\nimport de.techdev.trackr.domain.employee.sickdays.SickDays;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.project.billtimes.BillableTime;\nimport de.techdev.trackr.domain.project.invoice.Invoice;\nimport de.techdev.trackr.domain.project.worktimes.WorkTime;\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.support.ReloadableResourceBundleMessageSource;\nimport org.springframework.core.convert.support.ConfigurableConversionService;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.core.event.ValidatingRepositoryEventListener;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;\nimport org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;\n\n@Configuration\npublic class ApiRepositoryRestConfiguration extends RepositoryRestConfigurerAdapter {\n\n    @Override\n    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {\n        config.exposeIdsFor(Employee.class, Company.class, ContactPerson.class,\n                Address.class, Project.class, WorkTime.class, BillableTime.class, VacationRequest.class, TravelExpense.class,\n                Report.class, Comment.class, Invoice.class, SickDays.class);\n        config.setReturnBodyOnUpdate(true);\n        config.setReturnBodyOnCreate(true);\n    }\n\n    @Override\n    public void configureConversionService(ConfigurableConversionService conversionService) {\n        super.configureConversionService(conversionService);\n        conversionService.addConverter(dateConverter());\n    }\n\n    @Bean\n    public DateConverter dateConverter() {\n        return new DateConverter();\n    }\n\n    /**\n     * Add the validator to spring data rest.\n     */\n    @Override\n    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {\n        validatingListener.addValidator(\"beforeSave\", validator());\n        validatingListener.addValidator(\"beforeCreate\", validator());\n    }\n\n    /**\n     * Custom validator that extracts messages with locale. Used by spring-data-rest.\n     */\n    @Bean\n    public LocalValidatorFactoryBean validator() {\n        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();\n        localValidatorFactoryBean.setValidationMessageSource(messageSource());\n        return localValidatorFactoryBean;\n    }\n\n    /**\n     * Load all messages, reload when locale changes.\n     */\n    @Bean\n    public MessageSource messageSource() {\n        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();\n        messageSource.setBasenames(\"classpath:org/hibernate/validator/ValidationMessages\", \"classpath:/i18n/validation/messages\");\n        return messageSource;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/ApiWebMvcConfiguration.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport de.techdev.trackr.core.web.converters.DateConverter;\nimport de.techdev.trackr.domain.common.EmployeeSettingsLocaleResolver;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;\nimport org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;\nimport org.springframework.format.FormatterRegistry;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.LocaleResolver;\n\nimport java.util.List;\n\n@Configuration\npublic class ApiWebMvcConfiguration extends RepositoryRestMvcConfiguration {\n\n    @Autowired\n    private DateConverter dateConverter;\n\n    /**\n     * The self HREF for entities contains {?projection} to indicate the parameter is available, but we don't want that.\n     * The {@link RepositoryEntityLinksWithoutProjection} switches {?projection} off.\n     */\n    @Override\n    @Bean\n    public RepositoryEntityLinks entityLinks() {\n        ArgumentResolverPagingAndSortingTemplateVariables variables = new ArgumentResolverPagingAndSortingTemplateVariables(this.pageableResolver(), this.sortResolver());\n        return new RepositoryEntityLinksWithoutProjection(repositories(), resourceMappings(), config(), variables, backendIdConverterRegistry());\n    }\n\n    @Bean\n    public LocaleResolver localeResolver() {\n        return new EmployeeSettingsLocaleResolver();\n    }\n\n    @Override\n    public void addFormatters(FormatterRegistry registry) {\n        // super call is needed so the DomainClassConverter is used for linked resources\n        // (e.g. companies/0/address). The super class will configure the DomainClassConverter correctly only with this\n        // super call.\n        super.addFormatters(registry);\n        // We need to add the converter so non-Spring-Data-REST calls also use it.\n        registry.addConverter(dateConverter);\n    }\n\n    /**\n     * Needed for mapping exceptions in jackson that otherwise would get an ugly error message.\n     */\n    @Bean\n    public JsonMappingHandlerExceptionResolver jsonMappingHandlerExceptionResolver() {\n        return new JsonMappingHandlerExceptionResolver();\n    }\n\n    @Override\n    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {\n        exceptionResolvers.add(jsonMappingHandlerExceptionResolver());\n        super.extendHandlerExceptionResolvers(exceptionResolvers);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/ArgumentResolverPagingAndSortingTemplateVariables.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;\nimport org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver;\nimport org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver;\nimport org.springframework.hateoas.TemplateVariables;\nimport org.springframework.util.Assert;\nimport org.springframework.web.util.UriComponents;\nimport org.springframework.web.util.UriComponentsBuilder;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * Copy from Spring because thankfully they made it package protected. Nice!\n *\n * @deprecated See {@link RepositoryEntityLinksWithoutProjection}\n */\n@Deprecated\nclass ArgumentResolverPagingAndSortingTemplateVariables implements PagingAndSortingTemplateVariables {\n    private static final Set<Class<?>> SUPPORTED_TYPES = Collections.unmodifiableSet(new HashSet(Arrays.asList(new Class[]{Pageable.class, Sort.class})));\n    private final HateoasPageableHandlerMethodArgumentResolver pagingResolver;\n    private final HateoasSortHandlerMethodArgumentResolver sortResolver;\n\n    public ArgumentResolverPagingAndSortingTemplateVariables(HateoasPageableHandlerMethodArgumentResolver pagingResolver, HateoasSortHandlerMethodArgumentResolver sortResolver) {\n        Assert.notNull(pagingResolver, \"HateoasPageableHandlerMethodArgumentResolver must not be null!\");\n        Assert.notNull(sortResolver, \"HateoasSortHandlerMethodArgumentResolver must not be null!\");\n        this.pagingResolver = pagingResolver;\n        this.sortResolver = sortResolver;\n    }\n\n    public TemplateVariables getPaginationTemplateVariables(MethodParameter parameter, UriComponents components) {\n        return this.pagingResolver.getPaginationTemplateVariables(parameter, components);\n    }\n\n    public TemplateVariables getSortTemplateVariables(MethodParameter parameter, UriComponents template) {\n        return this.sortResolver.getSortTemplateVariables(parameter, template);\n    }\n\n    public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) {\n        if(value instanceof Pageable) {\n            this.pagingResolver.enhance(builder, parameter, value);\n        } else if(value instanceof Sort) {\n            this.sortResolver.enhance(builder, parameter, value);\n        }\n\n    }\n\n    public boolean supportsParameter(MethodParameter parameter) {\n        return SUPPORTED_TYPES.contains(parameter.getParameterType());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/ExceptionHandlers.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.MessageSource;\nimport org.springframework.context.support.MessageSourceAccessor;\nimport org.springframework.data.rest.core.RepositoryConstraintViolationException;\nimport org.springframework.data.rest.webmvc.support.RepositoryConstraintViolationExceptionMessage;\nimport org.springframework.orm.jpa.JpaSystemException;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\nimport static org.springframework.http.HttpStatus.BAD_REQUEST;\nimport static org.springframework.http.HttpStatus.CONFLICT;\n\n/**\n * @author Moritz Schulze\n */\n@ControllerAdvice\n@Slf4j\npublic class ExceptionHandlers {\n\n    private final MessageSourceAccessor messageSourceAccessor;\n\n    @Autowired\n    public ExceptionHandlers(MessageSource messageSource) {\n        this.messageSourceAccessor = new MessageSourceAccessor(messageSource);\n    }\n\n    /**\n     * This exception handler <i>should</i> handle violations of unique constraints.\n     * TODO: JpaSystemException is really broad, we need to check somehow that this only gets invoked for unique constraint violations\n     * @param e The exception to handle\n     * @return An error message\n     */\n    @ExceptionHandler(JpaSystemException.class)\n    @ResponseBody\n    @ResponseStatus(CONFLICT)\n    public String handleJpaSystemException(JpaSystemException e) {\n        return e.getMostSpecificCause().getMessage();\n    }\n\n    /**\n     * This is for custom controllers (i.e. not spring-data-rest) that do validation.\n     * @param ex The {@link org.springframework.data.rest.core.RepositoryConstraintViolationException} thrown by the controller.\n     * @return A map of fieldnames to FieldErrors\n     */\n    @ResponseBody\n    @ResponseStatus(BAD_REQUEST)\n    @ExceptionHandler(RepositoryConstraintViolationException.class)\n    public RepositoryConstraintViolationExceptionMessage handleRepositoryConstraintViolationException(RepositoryConstraintViolationException ex) {\n        return new RepositoryConstraintViolationExceptionMessage(ex, messageSourceAccessor);\n    }\n}"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/JsonMappingHandlerExceptionResolver.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport com.fasterxml.jackson.databind.JsonMappingException;\nimport com.fasterxml.jackson.databind.exc.InvalidFormatException;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.converter.HttpMessageNotReadableException;\nimport org.springframework.web.servlet.HandlerExceptionResolver;\nimport org.springframework.web.servlet.ModelAndView;\n\nimport javax.json.Json;\nimport javax.json.stream.JsonGenerator;\nimport javax.json.stream.JsonGeneratorFactory;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.Writer;\n\nimport static java.util.stream.Collectors.reducing;\n\n/**\n * 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}\n * exception handlers.\n *\n * @author Moritz Schulze\n */\npublic class JsonMappingHandlerExceptionResolver implements HandlerExceptionResolver {\n\n    protected JsonGeneratorFactory jsonGeneratorFactory;\n\n    public JsonMappingHandlerExceptionResolver() {\n        jsonGeneratorFactory = Json.createGeneratorFactory(null);\n    }\n\n    @Override\n    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {\n        if (HttpMessageNotReadableException.class.isAssignableFrom(ex.getClass()) &&\n                ex.getCause() != null && InvalidFormatException.class.isAssignableFrom(ex.getCause().getClass())) {\n            Writer outputWriter;\n            try {\n                outputWriter = response.getWriter();\n            } catch (IOException e) {\n                throw new IllegalStateException(\"Could not open response writer\", e);\n            }\n            response.setStatus(HttpStatus.BAD_REQUEST.value());\n            response.setHeader(\"Content-Type\", MediaType.APPLICATION_JSON_VALUE);\n            writeExceptionAsJsonToOutput((InvalidFormatException) ex.getCause(), outputWriter);\n            try {\n                outputWriter.flush();\n                outputWriter.close();\n            } catch (IOException e) {\n                throw new IllegalStateException(\"Could not flush and close response writer\", e);\n            }\n            return new ModelAndView();\n        }\n        return null;\n    }\n\n    /**\n     * Writes the information in the exception as a JSON object like this: { \"employee.salary\": { \"defaultMessage\": \"Cannot construct float from this value\"}}\n     * to a writer.\n     *\n     * @param ex     The exception thrown by Jackson\n     * @param writer The output writer to write to.\n     */\n    protected void writeExceptionAsJsonToOutput(InvalidFormatException ex, Writer writer) {\n        JsonGenerator jsonGenerator = jsonGeneratorFactory.createGenerator(writer);\n        jsonGenerator.writeStartObject()\n                     .writeStartArray(\"errors\")\n                     .writeStartObject()\n                     .write(\"property\", getFieldPath(ex))\n                     .write(\"message\", ex.getOriginalMessage())\n                .writeEnd() //object in array\n                .writeEnd() //array\n                .writeEnd().close();\n    }\n\n    /**\n     * Appends all fieldNames in the path of the exception to a string connected with dots.\n     *\n     * @param ex The exception containing the path information\n     * @return E.g. \"employee.firstName\"\n     */\n    private String getFieldPath(InvalidFormatException ex) {\n        return ex.getPath().stream().collect(\n                reducing(null, //start value\n                        JsonMappingException.Reference::getFieldName, //mapping of one Reference\n                        (s, s2) -> s == null ? s2 : s + \".\" + s2) //concatenate two strings, prohibit dot at the start of the result\n        );\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/api/RepositoryEntityLinksWithoutProjection.java",
    "content": "package de.techdev.trackr.core.web.api;\n\nimport org.springframework.data.repository.support.Repositories;\nimport org.springframework.data.rest.core.config.RepositoryRestConfiguration;\nimport org.springframework.data.rest.core.mapping.ResourceMappings;\nimport org.springframework.data.rest.core.mapping.ResourceMetadata;\nimport org.springframework.data.rest.webmvc.spi.BackendIdConverter;\nimport org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;\nimport org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;\nimport org.springframework.hateoas.Link;\nimport org.springframework.plugin.core.PluginRegistry;\nimport org.springframework.util.Assert;\n\nimport java.io.Serializable;\n\n/**\n * Overrides the {@link #linkToSingleResource(Class, Object)} method to not include {?projection}.\n * @author Moritz Schulze\n * @deprecated We really should make the frontend not rely on this and just remove it all together. For the migration to\n *             Spring Boot 1.3.3 it's left in so the REST API is as before as much as possible.\n */\n@Deprecated\npublic class RepositoryEntityLinksWithoutProjection extends RepositoryEntityLinks {\n\n    private final ResourceMappings mappings;\n    private final PluginRegistry<BackendIdConverter, Class<?>> idConverters;\n\n    /**\n     * Creates a new {@link org.springframework.data.rest.webmvc.support.RepositoryEntityLinks}.\n     *\n     * @param repositories must not be {@literal null}.\n     * @param mappings     must not be {@literal null}.\n     * @param config       must not be {@literal null}.\n     * @param variables     must not be {@literal null}.\n     * @param idConverters must not be {@literal null}.\n     */\n    public RepositoryEntityLinksWithoutProjection(Repositories repositories, ResourceMappings mappings, RepositoryRestConfiguration config, PagingAndSortingTemplateVariables variables, PluginRegistry<BackendIdConverter, Class<?>> idConverters) {\n        super(repositories, mappings, config, variables, idConverters);\n        this.mappings = mappings;\n        this.idConverters = idConverters;\n    }\n\n    @Override\n    public Link linkToSingleResource(Class<?> type, Object id) {\n        Assert.isInstanceOf(Serializable.class, id, \"Id must be assignable to Serializable!\");\n        ResourceMetadata metadata = mappings.getMetadataFor(type);\n        String mappedId = idConverters.getPluginFor(type, BackendIdConverter.DefaultIdConverter.INSTANCE).toRequestId((Serializable) id, type);\n        return linkFor(type).slash(mappedId).withRel(metadata.getItemResourceRel());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/core/web/converters/DateConverter.java",
    "content": "package de.techdev.trackr.core.web.converters;\n\nimport org.springframework.core.convert.converter.Converter;\n\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * A {@link java.util.Date} converter that supports the formats yyyy-MM-dd and yyyy-MM-dd HH:mm:ss.\n *\n * @author Moritz Schulze\n */\npublic class DateConverter implements Converter<String, Date> {\n\n    private DateFormat date10;\n\n    private DateFormat date19;\n\n    public DateConverter() {\n        date10 = new SimpleDateFormat(\"yyyy-MM-dd\");\n        date19 = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n    }\n\n    @Override\n    public Date convert(String source) {\n        if(source == null) {\n            return null;\n        }\n        Date date;\n        try {\n            Long milliSeconds = Long.valueOf(source);\n            return new Date(milliSeconds);\n        } catch (NumberFormatException e) {\n            //Continue with other formats\n        }\n        if(source.length() == 10) {\n            try {\n                date = date10.parse(source);\n            } catch (ParseException e) {\n                throw new IllegalArgumentException(String.format(\"%s is not a valid yyyy-MM-dd date.\", source), e);\n            }\n        } else if(source.length() == 19) {\n            try {\n                date = date19.parse(source);\n            } catch (ParseException e) {\n                throw new IllegalArgumentException(String.format(\"%s is not a valid yyyy-MM-dd HH:mm:ss date.\", source), e);\n            }\n        } else {\n            throw new IllegalArgumentException(String.format(\"%s is not convertible by this Date converter\", source));\n        }\n        return date;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/ApiBeansConfiguration.java",
    "content": "package de.techdev.trackr.domain;\n\nimport de.techdev.trackr.core.pdf.PdfRenderer;\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techdev.trackr.domain.employee.expenses.reports.ReportNotifyService;\nimport de.techdev.trackr.domain.employee.expenses.reports.ReportService;\nimport de.techdev.trackr.domain.employee.login.support.SupervisorService;\nimport de.techdev.trackr.domain.employee.sickdays.SickDaysNotifyService;\nimport de.techdev.trackr.domain.employee.vacation.HolidayCalculator;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequestApproveService;\nimport de.techdev.trackr.domain.employee.vacation.support.VacationRequestEmployeeToDaysTotalService;\nimport de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;\nimport de.techdev.trackr.domain.employee.worktimetracking.WorkTimeTrackingReminderService;\nimport de.techdev.trackr.domain.project.invoice.ChangeStateService;\nimport de.techdev.trackr.domain.project.invoice.InvoiceOverdueService;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.FilterType;\nimport org.springframework.data.rest.core.annotation.RepositoryEventHandler;\n\n/**\n * All Beans needed for the API that have nothing to do with web.\n */\n@Configuration\n@ComponentScan(includeFilters = {\n        @ComponentScan.Filter(type = FilterType.ANNOTATION, value = RepositoryEventHandler.class)\n})\npublic class ApiBeansConfiguration {\n\n    @Bean\n    public ReportService travelExpenseReportService() {\n        return new ReportService();\n    }\n\n    @Bean\n    public ReportNotifyService travelExpenseReportNotifyService() {\n        return new ReportNotifyService();\n    }\n\n    @Bean\n    public WorkTimeTrackingReminderService workTimeTrackingReminderService() {\n        return new WorkTimeTrackingReminderService();\n    }\n\n    @Bean\n    public VacationRequestNotifyService vacationRequestNotifyService() {\n        return new VacationRequestNotifyService();\n    }\n\n    @Bean\n    public VacationRequestApproveService vacationRequestService() {\n        return new VacationRequestApproveService();\n    }\n\n    @Bean\n    public VacationRequestEmployeeToDaysTotalService vacationRequestEmployeeToDaysTotalService() {\n        return new VacationRequestEmployeeToDaysTotalService();\n    }\n\n    @Bean\n    public HolidayCalculator holidayCalculator() {\n        return new HolidayCalculator();\n    }\n\n    @Bean\n    public InvoiceOverdueService invoiceOverdueService() {\n        return new InvoiceOverdueService();\n    }\n\n    @Bean\n    public ChangeStateService changeStateService() {\n        return new ChangeStateService();\n    }\n\n    @Bean\n    public SickDaysNotifyService sickDaysNotifyService() {\n        return new SickDaysNotifyService();\n    }\n\n    @Bean\n    public SupervisorService supervisorService() {\n        return new SupervisorService();\n    }\n\n    @Bean\n    public PdfRenderer pdfRenderer() {\n        return new PdfRenderer();\n    }\n\n    @Bean\n    public UuidMapper uuidMapper() {\n        return new UuidMapper();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/common/EmployeeSettingsLocaleResolver.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.trackr.domain.employee.Settings;\nimport de.techdev.trackr.domain.employee.SettingsRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.i18n.LocaleContext;\nimport org.springframework.context.i18n.LocaleContextHolder;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.context.SecurityContextHolder;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.web.servlet.LocaleContextResolver;\nimport org.springframework.web.servlet.i18n.SessionLocaleResolver;\nimport org.springframework.web.util.WebUtils;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.Locale;\n\npublic class EmployeeSettingsLocaleResolver implements LocaleContextResolver {\n\n    @Autowired\n    private SettingsRepository settingsRepository;\n\n    @Override\n    public Locale resolveLocale(HttpServletRequest request) {\n        return getLocaleFromSessionOrAuthentication(request);\n    }\n\n    @Override\n    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {\n        if(locale != null) {\n            WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);\n        }\n    }\n\n    @Override\n    public LocaleContext resolveLocaleContext(HttpServletRequest request) {\n        final Locale locale = getLocaleFromSessionOrAuthentication(request);\n        LocaleContext localeContext = () -> locale;\n        LocaleContextHolder.setLocaleContext(localeContext);\n        return localeContext;\n    }\n\n    @Override\n    public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {\n        if(localeContext != null) {\n            Locale locale = localeContext.getLocale();\n            WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);\n        }\n    }\n\n    /**\n     * Tries to extract the locale from the session. If not present it extracts the locale from the logged in user. Defaults to english.\n     * @param request The request\n     * @return The extracted locale, default {@link java.util.Locale#ENGLISH}.\n     */\n    protected Locale getLocaleFromSessionOrAuthentication(HttpServletRequest request) {\n        Locale locale = (Locale) WebUtils.getSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);\n        if(locale == null) {\n            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();\n            if(authentication != null) {\n                Object principal = authentication.getPrincipal();\n                if (User.class.isAssignableFrom(principal.getClass())) {\n                    String username = ((User) principal).getUsername();\n                    Settings localeSetting = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, username);\n                    if (localeSetting != null) {\n                        locale = Locale.forLanguageTag(localeSetting.getValue());\n                    }\n                }\n            }\n            //Either no authentication or admin user\n            if(locale == null) {\n                locale = Locale.ENGLISH;\n            }\n            WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);\n        }\n        LocaleContextHolder.setLocale(locale);\n        return locale;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/common/FederalState.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport com.fasterxml.jackson.annotation.JsonFormat;\n\n/**\n * @author Moritz Schulze\n */\n@JsonFormat(shape= JsonFormat.Shape.OBJECT)\npublic enum FederalState {\n\n    BADEN_WUERTTEMBERG(\"Baden-Württemberg\"), BAYERN(\"Bayern\"), BERLIN(\"Berlin\"), BRANDENBURG(\"Brandenburg\"), BREMEN(\"Bremen\"),\n    HAMBURG(\"Hamburg\"), HESSEN(\"Hessen\"), MECKLENBURG_VORPOMMERN(\"Mecklenburg-Vorpommern\"), NIEDERSACHSEN(\"Niedersachsen\"), NORDRHEIN_WESTFALEN(\"Nordrhein-Westfalen\"),\n    RHEINLAND_PFALZ(\"Rheinland-Pfalz\"), SAARLAND(\"Saarland\"), SACHSEN(\"Sachsen\"), SACHSEN_ANHALT(\"Sachsen-Anhalt\"), SCHLESWIG_HOLSTEIN(\"Schleswig-Holstein\"), THUERINGEN(\"Thüringen\");\n\n    private String state;\n\n    FederalState(String state) {\n        this.state = state;\n    }\n\n    public String getState() {\n        return state;\n    }\n\n    public String getName() {\n        return this.toString();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/common/FederalStateController.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static java.util.Arrays.asList;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/federalStates\")\npublic class FederalStateController {\n\n    @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    @ResponseBody\n    public List<FederalState> federalStates() {\n        return asList(FederalState.values());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/common/UuidMapper.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.UUID;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * @author Moritz Schulze\n */\npublic class UuidMapper {\n\n    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}).*$\");\n\n    @Autowired\n    private DataSource dataSource;\n\n    public String extractUUIDFromString(String input) {\n        Matcher matcher = UuidMapper.UUID_PATTERN.matcher(input);\n        if (matcher.matches()) {\n            return matcher.group(1);\n        } else {\n            return null;\n        }\n    }\n\n    public Long getIdFromUUID(String uuid) {\n        Long id = null;\n        try(Connection connection = dataSource.getConnection();\n            PreparedStatement getIdStatement = connection.prepareStatement(\"SELECT id FROM uuid_mapping WHERE uuid = ?\")) {\n            getIdStatement.setString(1, uuid);\n            ResultSet resultSet = getIdStatement.executeQuery();\n            if (resultSet.next()) {\n                id = resultSet.getLong(1);\n            }\n        } catch (SQLException e) {\n            // just return null\n        }\n        return id;\n    }\n\n    public void deleteUUID(String uuid) {\n        try(Connection connection = dataSource.getConnection();\n            PreparedStatement deleteStatement = connection.prepareStatement(\"DELETE FROM uuid_mapping WHERE uuid = ?\")) {\n            deleteStatement.setString(1, uuid);\n            deleteStatement.execute();\n        } catch (SQLException e) {\n            // nothing to do\n        }\n    }\n\n    public void deleteUUID(Long id) {\n        try(Connection connection = dataSource.getConnection();\n            PreparedStatement deleteStatement = connection.prepareStatement(\"DELETE FROM uuid_mapping WHERE id = ?\")) {\n            deleteStatement.setLong(1, id);\n            deleteStatement.execute();\n        } catch (SQLException e) {\n            // nothing to do\n        }\n    }\n\n    public UUID createUUID(Long id) {\n        UUID uuid = UUID.randomUUID();\n        try(Connection connection = dataSource.getConnection();\n            PreparedStatement insertStatement = connection.prepareStatement(\"INSERT INTO uuid_mapping (id, uuid) VALUES (?, ?)\")) {\n            insertStatement.setLong(1, id);\n            insertStatement.setString(2, uuid.toString());\n            insertStatement.execute();\n        } catch (SQLException e) {\n            return null;\n        }\n        return uuid;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/Address.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\n\n@Entity\n@Getter\n@Setter\npublic class Address {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotEmpty\n    private String street;\n\n    @NotEmpty\n    private String houseNumber;\n\n    @NotEmpty\n    private String zipCode;\n\n    @NotEmpty\n    private String city;\n\n    @NotEmpty\n    private String country;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/AddressEventHandler.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.HandleBeforeCreate;\nimport org.springframework.data.rest.core.annotation.HandleBeforeDelete;\nimport org.springframework.data.rest.core.annotation.HandleBeforeSave;\nimport org.springframework.data.rest.core.annotation.RepositoryEventHandler;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n/**\n * This class prevents other users than admins from creating, updating or deleting addresses.\n * <p>\n * 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}\n * gets an address too this will have to be thought over.\n *\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(Address.class)\n@SuppressWarnings(\"unused\")\npublic class AddressEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkSaveAuthority(Address address) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkUpdateAuthority(Address address) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkDeleteAuthority(Address address) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/AddressRepository.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.rest.core.annotation.RestResource;\n\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic interface AddressRepository extends JpaRepository<Address, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    List<Address> findAll();\n\n    @Override\n    @RestResource(exported = false)\n    Page<Address> findAll(Pageable pageable);\n\n    @Override\n    @RestResource(exported = false)\n    List<Address> findAll(Sort sort);\n\n    @Override\n    @RestResource(exported = false)\n    void delete(Long aLong);\n\n    @Override\n    @RestResource(exported = false)\n    void delete(Address entity);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/Company.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.techdev.trackr.domain.project.Project;\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.DecimalMin;\nimport javax.validation.constraints.NotNull;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@Getter\n@Setter\n@EqualsAndHashCode(exclude = \"contactPersons\")\n@Entity\n@JsonIgnoreProperties({\"debitorProjects\"})\npublic class Company {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotNull\n    @DecimalMin(\"0\")\n    @Column(unique = true)\n    private Long companyId;\n\n    @NotEmpty\n    private String name;\n\n    /**\n     * Full days that the company has to pay their invoices.\n     */\n    private Integer timeForPayment;\n\n    @NotNull\n    @OneToOne(cascade = CascadeType.PERSIST)\n    @JoinColumn(name = \"address_id\")\n    private Address address;\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"company\")\n    private List<ContactPerson> contactPersons = new ArrayList<>();\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"company\")\n    private List<Project> projects = new ArrayList<>();\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"debitor\")\n    private List<Project> debitorProjects = new ArrayList<>();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/CompanyEventHandler.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(Company.class)\n@SuppressWarnings(\"unused\")\npublic class CompanyEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkSaveAuthority(Company company) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkUpdateAuthority(Company company) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkDeleteAuthority(Company company) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void beforeAddContactPerson(Company company, List<ContactPerson> contactPersons) {\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void beforeDeleteContactPerson(Company company, Object contactPerson) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/CompanyRepository.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryRestResource(path = \"/companies\")\npublic interface CompanyRepository extends JpaRepository<Company, Long> {\n\n    Company findByCompanyId(@Param(\"companyId\") Long companyId);\n\n    List<Company> findByNameLikeIgnoreCaseOrderByNameAsc(@Param(\"name\") String name);\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/CompanyWithAddressAndContactPersonsProjection.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = Company.class, name = \"withAddressAndContactPersons\")\npublic interface CompanyWithAddressAndContactPersonsProjection {\n\n    Long getId();\n\n    Integer getVersion();\n\n    Long getCompanyId();\n\n    String getName();\n\n    Integer getTimeForPayment();\n\n    Address getAddress();\n\n    List<ContactPerson> getContactPersons();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/ContactPerson.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.Email;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\npublic class ContactPerson {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotNull\n    @ManyToOne\n    @JoinColumn(name = \"company\")\n    private Company company;\n\n    @Email\n    private String email;\n\n    @NotEmpty\n    private String firstName;\n\n    @NotEmpty\n    private String lastName;\n\n    private String phone;\n\n    @NotEmpty\n    private String salutation;\n\n    private String roles;\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/ContactPersonEventHandler.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(ContactPerson.class)\n@SuppressWarnings(\"unused\")\npublic class ContactPersonEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkCreateAuthority(ContactPerson contactPerson) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkUpdateAuthority(ContactPerson contactPerson) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkDeleteAuthority(ContactPerson contactPerson) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkLinkUpdateAuthority(ContactPerson contactPerson, Object links) {\n        // only security check\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkDeleteAuthority(ContactPerson contactPerson, Object linkedEntity) {\n        // only security check\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/company/ContactPersonRepository.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport org.springframework.data.repository.CrudRepository;\n\n/**\n * @author Moritz Schulze\n */\npublic interface ContactPersonRepository extends CrudRepository<ContactPerson, Long> {\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/Employee.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport de.techdev.trackr.domain.project.billtimes.BillableTime;\nimport de.techdev.trackr.domain.project.worktimes.WorkTime;\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.Email;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * Represents any employee of techdev.\n */\n@Entity\n@Getter\n@Setter\n@JsonIgnoreProperties({\"credential\", \"workTimes\", \"billableTimes\", \"vacationRequests\", \"approvedRequests\", \"travelExpenseReports\"})\n@EndAfterBegin(begin = \"joinDate\", end = \"leaveDate\")\npublic class Employee {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotEmpty\n    private String firstName;\n\n    @NotEmpty\n    private String lastName;\n\n    @Column(unique = true)\n    @Email\n    @NotEmpty\n    private String email;\n\n    private String phoneNumber;\n\n    private String title;\n\n    private BigDecimal salary;\n\n    private BigDecimal hourlyCostRate;\n\n    @Temporal(TemporalType.DATE)\n    private Date joinDate;\n\n    @Temporal(TemporalType.DATE)\n    private Date leaveDate;\n\n    @Enumerated(EnumType.STRING)\n    @NotNull\n    private FederalState federalState;\n\n    private Float vacationEntitlement;\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"employee\")\n    private List<WorkTime> workTimes = new ArrayList<>();\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"employee\")\n    private List<BillableTime> billableTimes = new ArrayList<>();\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"employee\")\n    private List<VacationRequest> vacationRequests;\n\n    @OneToMany(mappedBy = \"approver\")\n    private List<VacationRequest> approvedRequests;\n\n    @OneToMany(mappedBy = \"employee\")\n    private List<Report> travelExpenseReports;\n\n    @OneToOne(orphanRemoval = true)\n    private Address address;\n\n    private boolean deleted;\n\n    public String fullName() {\n        return getFirstName() + \" \" + getLastName();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeController.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.rest.core.RepositoryConstraintViolationException;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\n\n/**\n * A controller for special operations on Employees not exportable by spring-data-rest\n */\n@Controller\n@RequestMapping(value = \"/employees\")\npublic class EmployeeController {\n\n    @Autowired\n    private SelfEmployeeRepository employeeRepository;\n\n    /**\n     * This method allows an employee to change some values of his entity on his own, namely the one\n     * in SelfEmployee.\n     *\n     * @param employee The employee to edit.\n     * @param selfEmployee The request body, i.e. the data to change\n     * @return The updated data.\n     */\n    @ResponseBody\n    @RequestMapping(value = \"/{employee}/self\", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)\n    public SelfEmployee updateSelf(@PathVariable(\"employee\") Long employee,\n                                   @RequestBody @Valid SelfEmployee selfEmployee,\n                                   BindingResult bindingResult) {\n        if (bindingResult.hasErrors()) {\n            throw new RepositoryConstraintViolationException(bindingResult);\n        }\n        return SelfEmployee.valueOf(employeeRepository.save(employee, selfEmployee));\n    }\n\n    @RequestMapping(value = \"/{employee}/self\", method = {RequestMethod.GET})\n    @ResponseBody\n    public SelfEmployee get(@PathVariable(\"employee\") Long employeeId) {\n        return employeeRepository.findOne(employeeId);\n    }\n}"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n@RepositoryEventHandler(Employee.class)\n@SuppressWarnings(\"unused\")\npublic class EmployeeEventHandler {\n\n    @Autowired\n    private SettingsRepository settingsRepository;\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkCreateAuthority(Employee employee) {\n    }\n\n    @HandleAfterCreate\n    public void createInitialSettings(Employee employee) {\n        Settings settings = new Settings();\n        settings.setEmployee(employee);\n        settings.setType(Settings.SettingsType.LOCALE);\n        settings.setValue(\"de\");\n        settingsRepository.save(settings);\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkUpdateAuthority(Employee employee) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkDeleteAuthority(Employee employee) {\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void deleteCredentialForbidden(Employee employee, Object credential) {\n        //deny all, cannot be called\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeRepository.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.List;\n\npublic interface EmployeeRepository extends JpaRepository<Employee, Long> {\n\n    @Override\n    @PostAuthorize(\"hasRole('ROLE_SUPERVISOR') or returnObject?.email == principal?.username\")\n    Employee findOne(@Param(\"id\") Long id);\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<Employee> findAll();\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<Employee> findAll(Sort sort);\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<Employee> findAll(Iterable<Long> longs);\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    Page<Employee> findAll(Pageable pageable);\n\n    @RestResource(exported = false)\n    List<Employee> findByFederalState(FederalState berlin);\n\n    /**\n     * Not exported find all method to access all employees without the need for SUPERVISOR/ADMIN rights.\n     *\n     * Filters the admin out. Only used for the address book.\n     */\n    @RestResource(exported = false)\n    @Query(\"select e from Employee e where e.email <> 'admin@techdev.de' and e.deleted = false\")\n    Page<Employee> findAllForAddressBook(Pageable pageable);\n\n    @RestResource(exported = false)\n    Employee findByEmail(String email);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/EmployeeScheduledJob.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.employee.worktimetracking.WorkTimeTrackingReminderService;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\n\n@Slf4j\n@Setter\npublic class EmployeeScheduledJob {\n\n    @Autowired\n    private WorkTimeTrackingReminderService workTimeTrackingReminderService;\n\n    /**\n     * Task that gets triggered in {@link de.techdev.trackr.domain.scheduling.ScheduledJobsConfiguration} by a custom trigger.\n     *\n     * @param state The federal state to send out reminders for.\n     * @return A task that reminds employees in the federal state to track their working times.\n     */\n    public Runnable sendWorkTimeReminderTask(FederalState state) {\n        return () -> workTimeTrackingReminderService.remindEmployeesToTrackWorkTimes(state);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/Projections.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.company.Address;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.math.BigDecimal;\nimport java.util.Date;\n\npublic class Projections {\n\n    @Projection(types = Employee.class, name = \"withAddress\")\n    public interface WithAddressProjection {\n\n        Long getId();\n\n        Integer getVersion();\n\n        String getFirstName();\n\n        String getLastName();\n\n        String getEmail();\n\n        String getPhoneNumber();\n\n        String getTitle();\n\n        BigDecimal getSalary();\n\n        BigDecimal getHourlyCostRate();\n\n        Date getJoinDate();\n\n        Date getLeaveDate();\n\n        FederalState getFederalState();\n\n        Float getVacationEntitlement();\n\n        Address getAddress();\n\n        boolean isDeleted();\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/SelfEmployee.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.validation.Valid;\nimport java.math.BigDecimal;\n\n@Getter\n@Setter\npublic class SelfEmployee {\n\n    private Long id;\n\n    private Integer version;\n\n    @NotEmpty\n    private String firstName;\n\n    @NotEmpty\n    private String lastName;\n\n    private String phoneNumber;\n\n    private String title;\n\n    private BigDecimal salary;\n\n    @Valid\n    private Address address;\n\n    public static SelfEmployee valueOf(Employee employee) {\n        SelfEmployee selfEmployee = new SelfEmployee();\n        selfEmployee.setId(employee.getId());\n        selfEmployee.setFirstName(employee.getFirstName());\n        selfEmployee.setLastName(employee.getLastName());\n        selfEmployee.setPhoneNumber(employee.getPhoneNumber());\n        selfEmployee.setAddress(employee.getAddress());\n        selfEmployee.setVersion(employee.getVersion());\n        selfEmployee.setSalary(employee.getSalary());\n        selfEmployee.setTitle(employee.getTitle());\n        return selfEmployee;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/SelfEmployeeRepository.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.domain.company.AddressRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.stereotype.Repository;\nimport org.springframework.transaction.annotation.Transactional;\n\n@Repository\npublic class SelfEmployeeRepository {\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private AddressRepository addressRepository;\n\n    /**\n     * Update all values on an employee that an employee is allowed to update him/herself.\n     * This is the last name, first name, phone number and address.\n     * @param employeeId The id of the employee to update.\n     * @param selfEmployee The new data for the employee.\n     * @return The updated employee\n     */\n    @Transactional\n    @PostAuthorize(\"hasRole('ROLE_ADMIN') or returnObject.email == principal?.username\")\n    public Employee save(Long employeeId, SelfEmployee selfEmployee) {\n        Employee employee = employeeRepository.findOne(employeeId);\n        employee.setFirstName(selfEmployee.getFirstName());\n        employee.setLastName(selfEmployee.getLastName());\n        employee.setPhoneNumber(selfEmployee.getPhoneNumber());\n\n        if (selfEmployee.getAddress() != null) {\n            Address address = addressRepository.save(selfEmployee.getAddress());\n            employee.setAddress(address);\n        }\n\n        return employeeRepository.save(employee);\n    }\n\n    public SelfEmployee findOne(Long employeeId) {\n        return SelfEmployee.valueOf(employeeRepository.findOne(employeeId));\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/Settings.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\n\n@Entity\n@Getter\n@Setter\n@Table( uniqueConstraints = { @UniqueConstraint(columnNames = {\"type\", \"employee_id\"}) } )\npublic class Settings {\n\n    public enum SettingsType {\n        LOCALE\n    }\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Enumerated(EnumType.STRING)\n    private SettingsType type;\n\n    @NotEmpty\n    private String value;\n\n    @ManyToOne\n    @NotNull\n    @JoinColumn(name = \"employee_id\")\n    private Employee employee;\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/SettingsRepository.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport org.springframework.data.repository.Repository;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\n\nimport java.util.List;\n\n@RepositoryRestResource(exported = false)\npublic interface SettingsRepository extends Repository<Settings, Long> {\n\n    Settings save(Settings settings);\n\n    List<Settings> findByEmployee_Email(String email);\n\n    Settings findByTypeAndEmployee_Email(Settings.SettingsType type, String email);\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/addressbook/AddressBookController.java",
    "content": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.web.PageableDefault;\nimport org.springframework.hateoas.PagedResources;\nimport org.springframework.hateoas.Resources;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/address_book\")\npublic class AddressBookController {\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @PreAuthorize(\"hasRole('ROLE_EMPLOYEE')\")\n    @ResponseBody\n    @RequestMapping(method = RequestMethod.GET, produces = \"application/hal+json\")\n    public Resources<EmployeeForAddressBookDTO> getAddressList(\n            @PageableDefault(sort = \"lastName\") Pageable pageable\n    ) {\n        Page<Employee> pageOfEmployees = employeeRepository.findAllForAddressBook(pageable);\n        List<EmployeeForAddressBookDTO> employeeForAddressBookDTOs = transformToReducedEmployees(pageOfEmployees.getContent());\n        return new PagedResources<>(employeeForAddressBookDTOs, pageMetadataFromPage(pageOfEmployees));\n    }\n\n    /**\n     * Transform a list of employees to a list of reduced employees\n     *\n     * @param listOfEmployees The list to transform\n     * @return The transformed list.\n     */\n    protected List<EmployeeForAddressBookDTO> transformToReducedEmployees(List<Employee> listOfEmployees) {\n        return listOfEmployees\n                .stream()\n                .map(EmployeeForAddressBookDTO::valueOf)\n                .collect(Collectors.toList());\n    }\n\n    protected PagedResources.PageMetadata pageMetadataFromPage(Page page) {\n        return new PagedResources.PageMetadata(page.getSize(), page.getNumber(), page.getTotalElements(), page.getTotalPages());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/addressbook/EmployeeForAddressBookDTO.java",
    "content": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.domain.employee.Employee;\nimport lombok.Getter;\nimport lombok.Setter;\n\n/**\n * Employee only containing the information needed for the address book.\n */\n@Getter\n@Setter\nclass EmployeeForAddressBookDTO {\n\n    private Long id;\n\n    private String firstName;\n\n    private String lastName;\n\n    private String phoneNumber;\n\n    private String title;\n\n    private String email;\n\n    private Address address;\n\n    static EmployeeForAddressBookDTO valueOf(Employee employee) {\n        EmployeeForAddressBookDTO employeeForAddressBookDTO = new EmployeeForAddressBookDTO();\n        employeeForAddressBookDTO.setId(employee.getId());\n        employeeForAddressBookDTO.setFirstName(employee.getFirstName());\n        employeeForAddressBookDTO.setLastName(employee.getLastName());\n        employeeForAddressBookDTO.setPhoneNumber(employee.getPhoneNumber());\n        employeeForAddressBookDTO.setTitle(employee.getTitle());\n        employeeForAddressBookDTO.setEmail(employee.getEmail());\n        employeeForAddressBookDTO.setAddress(employee.getAddress());\n        return employeeForAddressBookDTO;\n    }\n}"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpense.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.math.BigDecimal;\nimport java.util.Date;\n\n@Getter\n@Setter\n@Entity\n@EndAfterBegin(begin = \"fromDate\", end = \"toDate\")\npublic class TravelExpense {\n\n    public enum Type {\n        HOTEL, TAXI, FLIGHT, TRAIN, PARKING, OEPNV, MILEAGE_ALLOWANCE, OTHER\n    }\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotNull\n    @ManyToOne\n    private Report report;\n\n    @NotNull\n    @Enumerated(EnumType.STRING)\n    private Type type;\n\n    @NotNull\n    private BigDecimal cost;\n\n    @NotNull\n    private BigDecimal vat;\n\n    @NotNull\n    @Temporal(TemporalType.DATE)\n    private Date fromDate;\n\n    @NotNull\n    @Temporal(TemporalType.DATE)\n    private Date toDate;\n\n    @NotNull\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date submissionDate;\n\n    private String comment;\n\n    private boolean paid;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n@RepositoryEventHandler(TravelExpense.class)\n@SuppressWarnings(\"unused\")\npublic class TravelExpenseEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"@travelExpenseEventHandler.canCreate(principal?.username, #travelExpense)\")\n    public void checkCreateAuthority(TravelExpense travelExpense) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or @travelExpenseEventHandler.canEdit(principal?.username, #travelExpense)\")\n    public void checkUpdateAuthority(TravelExpense travelExpense) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or @travelExpenseEventHandler.canDelete(principal?.username, #travelExpense)\")\n    public void checkDeleteAuthority(TravelExpense travelExpense) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"denyAll()\")\n    public void denyLinkSave(TravelExpense travelExpense, Object links) {\n        //links are not settable\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void denyLinkDelete(TravelExpense travelExpense, Object linkedEntity) {\n        //links are not deletable.\n    }\n\n    public boolean canCreate(String email, TravelExpense travelExpense) {\n        return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&\n                travelExpense.getReport().getStatus() != Report.Status.APPROVED &&\n                travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;\n    }\n\n    public boolean canEdit(String email, TravelExpense travelExpense) {\n        return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&\n                travelExpense.getReport().getStatus() != Report.Status.APPROVED &&\n                travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;\n    }\n\n    public boolean canDelete(String email, TravelExpense travelExpense) {\n        return email != null && email.equals(travelExpense.getReport().getEmployee().getEmail()) &&\n                travelExpense.getReport().getStatus() != Report.Status.APPROVED &&\n                travelExpense.getReport().getStatus() != Report.Status.SUBMITTED;\n    }\n}\n\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseRepository.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\n\n/**\n * @author Moritz Schulze\n */\npublic interface TravelExpenseRepository extends CrudRepository<TravelExpense, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    Iterable<TravelExpense> findAll();\n\n    @Override\n    @PostAuthorize(\"returnObject?.report.employee.email == principal?.username\")\n    TravelExpense findOne(Long aLong);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseTypeController.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\nimport static java.util.Arrays.asList;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/travelExpenses\")\npublic class TravelExpenseTypeController {\n\n    @ResponseBody\n    @RequestMapping(value = \"types\", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    public List<TravelExpense.Type> types() {\n        return asList(TravelExpense.Type.values());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Projections.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.expenses.TravelExpense;\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic class Projections {\n    @Projection(types = Report.class, name = \"overview\")\n    public interface TravelExpenseReportForOverviewProjection {\n        Long getId();\n\n        Employee getEmployee();\n\n        Report.Status getStatus();\n\n        List<TravelExpense> getExpenses();\n\n        Date getSubmissionDate();\n\n        Date getApprovalDate();\n\n        Employee getApprover();\n\n        Company getDebitor();\n\n        Project getProject();\n    }\n\n    @Projection(types = Report.class, name = \"withEmployeeAndExpenses\")\n    public interface TravelExpenseReportWithEmployeeAndTravelExpensesProjection {\n        Long getId();\n\n        Integer getVersion();\n\n        Employee getEmployee();\n\n        List<TravelExpense> getExpenses();\n\n        Report.Status getStatus();\n\n        Date getSubmissionDate();\n    }\n\n    @Projection(types = Report.class, name = \"withExpensesAndDebitor\")\n    public interface TravelExpenseReportWithExpensesAndDebitorProjection {\n        Long getId();\n\n        Integer getVersion();\n\n        List<TravelExpense> getExpenses();\n\n        Report.Status getStatus();\n\n        Date getSubmissionDate();\n\n        Date getApprovalDate();\n\n        Company getDebitor();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/Report.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.expenses.TravelExpense;\nimport de.techdev.trackr.domain.employee.expenses.reports.comments.Comment;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.validation.constraints.ProjectBelongsToCompany;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@Getter\n@Setter\n@Entity\n@Table(name = \"travelExpenseReport\")\n@ProjectBelongsToCompany(companyField = \"debitor\")\npublic class Report {\n\n    public enum Status {\n        SUBMITTED, PENDING, APPROVED, REJECTED\n    }\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @ManyToOne\n    private Employee employee;\n\n    @OneToMany(mappedBy = \"report\", cascade = CascadeType.ALL)\n    private List<TravelExpense> expenses = new ArrayList<>();\n\n    @Enumerated(EnumType.STRING)\n    private Status status;\n\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date submissionDate;\n\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date approvalDate;\n\n    @ManyToOne\n    private Employee approver;\n\n    @OneToMany(mappedBy = \"travelExpenseReport\", cascade = CascadeType.REMOVE)\n    private List<Comment> comments;\n\n    @ManyToOne(optional = false)\n    private Company debitor;\n\n    @ManyToOne\n    private Project project;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportController.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.core.pdf.PdfCreationException;\nimport de.techdev.trackr.core.pdf.PdfRenderer;\nimport de.techdev.trackr.domain.employee.expenses.TravelExpense;\nimport org.apache.commons.codec.binary.Base64;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.transaction.annotation.Transactional;\nimport org.springframework.web.bind.annotation.*;\nimport org.thymeleaf.context.Context;\n\nimport java.math.BigDecimal;\nimport java.security.Principal;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Optional;\n\n@Controller\n@RequestMapping(\"/travelExpenseReports\")\npublic class ReportController {\n\n    @Autowired\n    private ReportService travelExpenseReportService;\n\n    @Autowired\n    private PdfRenderer pdfRenderer;\n\n    @Autowired\n    private ReportRepository travelExpenseReportRepository;\n\n    @RequestMapping(value = \"/{id}/submit\", method = RequestMethod.PUT)\n    @ResponseBody\n    @ResponseStatus(HttpStatus.NO_CONTENT)\n    public void submit(@PathVariable(\"id\") Report travelExpenseReport) {\n        travelExpenseReportService.submit(travelExpenseReport);\n    }\n\n    @RequestMapping(value = \"/{id}/approve\", method = RequestMethod.PUT)\n    @ResponseBody\n    @ResponseStatus(HttpStatus.NO_CONTENT)\n    public void approve(@PathVariable(\"id\") Report travelExpenseReport, Principal principal) {\n        travelExpenseReportService.accept(travelExpenseReport, principal.getName());\n    }\n\n    @RequestMapping(value = \"/{id}/reject\", method = RequestMethod.PUT)\n    @ResponseBody\n    @ResponseStatus(HttpStatus.NO_CONTENT)\n    public void reject(@PathVariable(\"id\") Report travelExpenseReport, Principal principal) {\n        travelExpenseReportService.reject(travelExpenseReport, principal.getName());\n    }\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username\")\n    @RequestMapping(value = \"/{id}/pdf\", produces = \"application/pdf\")\n    @Transactional\n    public ResponseEntity<byte[]> asPdf(@PathVariable(\"id\") Report travelExpenseReport) {\n        Report report = travelExpenseReportRepository.findOne(travelExpenseReport.getId());\n\n        Context ctx = new Context();\n        ctx.setVariable(\"report\", report);\n        ctx.setVariable(\"today\", new Date());\n        List<TravelExpense> expenses = report.getExpenses();\n        BigDecimal totalCost = expenses.stream().map(TravelExpense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);\n        BigDecimal totalReimbursement = expenses.stream()\n                .filter(te -> !te.isPaid()).map(TravelExpense::getCost).reduce(BigDecimal.ZERO, BigDecimal::add);\n        ctx.setVariable(\"totalCost\", totalCost);\n        ctx.setVariable(\"totalReimbursement\", totalReimbursement);\n        Optional<Date> startDate = expenses.stream().map(TravelExpense::getFromDate).min(Date::compareTo);\n        Optional<Date> endDate = expenses.stream().map(TravelExpense::getToDate).max(Date::compareTo);\n        if (startDate.isPresent()) {\n            ctx.setVariable(\"startDate\", startDate.get());\n        }\n        if(endDate.isPresent()) {\n            ctx.setVariable(\"endDate\", endDate.get());\n        }\n        try {\n            byte[] pdf = pdfRenderer.renderPdf(\"travel-expenses/report\", ctx);\n            byte[] pdfBase64 = Base64.encodeBase64(pdf);\n            return new ResponseEntity<>(pdfBase64, HttpStatus.OK);\n        } catch (PdfCreationException e) {\n            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.AccessDeniedException;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n@RepositoryEventHandler(Report.class)\n@SuppressWarnings(\"unused\")\npublic class ReportEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"#travelExpenseReport.employee.email == principal?.username\")\n    public void checkCreateAuthority(Report travelExpenseReport) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkUpdateAuthority(Report travelExpenseReport) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"@reportEventHandler.employeeCanDeleteReport(#travelExpenseReport, principal?.username) or hasRole('ROLE_ADMIN')\")\n    public void checkDeleteAuthority(Report travelExpenseReport) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username\")\n    public void checkLinkSaveAuthority(Report travelExpenseReport, Object links) {\n        //TODO: links is the _old_ content of the link\n        //TODO: how to check for security? the employee should not be able to edit debitor/project but how do we check that?\n        //TODO: it is not possible to prohibit employees from editing links in general because it is used to add travel expenses.\n        if (links != null && Employee.class.isAssignableFrom(links.getClass())) {\n            throw new AccessDeniedException(\"Employee is not changeable on a travel expense report.\");\n        }\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username\")\n    public void checkLinkDeleteAuthority(Report travelExpenseReport, Object linkedEntity) {\n        if(travelExpenseReport.getEmployee() == null) {\n            throw new AccessDeniedException(\"Employee is not deletable on a travel expense report.\");\n        }\n    }\n\n    public boolean employeeCanDeleteReport(Report report, String username) {\n        return username != null && report.getEmployee().getEmail().equals(username) &&\n                (report.getStatus() == Report.Status.PENDING || report.getStatus() == Report.Status.REJECTED);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportNotifyService.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.expenses.TravelExpense;\nimport de.techdev.trackr.domain.employee.login.support.SupervisorService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.mail.SimpleMailMessage;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\npublic class ReportNotifyService {\n\n    @Autowired\n    private MailService mailService;\n\n    @Autowired\n    private SupervisorService supervisorService;\n\n    @Autowired\n    private ReportRepository travelExpenseReportRepository;\n\n    @Value(\"${trackr.frontendUrl}\")\n    private String frontendUrl;\n\n    /**\n     * Sends a mail to all supervisors except the owning for a submitted travel expense report.\n     *\n     * @param report The report for which the mail is to be sent.\n     */\n    public void notifySupervisorsOnSubmission(Report report) {\n        String[] emails = supervisorService.getSupervisorEmailsArrayWithout(email ->\n                        !report.getEmployee().getEmail().equals(email)\n        );\n\n        SimpleMailMessage mailMessage = new SimpleMailMessage();\n        mailMessage.setFrom(\"no-reply@techdev.de\");\n        mailMessage.setTo(emails);\n        mailMessage.setSubject(\"New travel expense report by \" + fullName(report.getEmployee()));\n        mailMessage.setText(\n                String.format(\"%s submitted a new travel expense report (#%d) totalling %.2f.\\n\\nGo to %s to approve or reject it.\",\n                        fullName(report.getEmployee()), report.getId(), getTotalAmount(report), getWebLink(report))\n        );\n        mailService.sendMail(mailMessage);\n    }\n\n    protected String getWebLink(Report report) {\n        return frontendUrl + \"/supervisor/expenses/\" + report.getId();\n    }\n\n    public void notifyEmployeeOnApproval(Report report) {\n        notifyEmployeeOnStatusChange(report, \"approved\");\n    }\n\n    public void notifyEmployeeOnRejection(Report report) {\n        notifyEmployeeOnStatusChange(report, \"rejected\");\n    }\n\n    private void notifyEmployeeOnStatusChange(Report report, String outcome) {\n        SimpleMailMessage mail = new SimpleMailMessage();\n        mail.setFrom(\"no-reply@techdev.de\");\n        mail.setTo(report.getEmployee().getEmail());\n        mail.setSubject(String.format(\"Your travel expense report has been %s\", outcome));\n        mail.setText(\n                String.format(\"%s has %s your travel expense report #%d.\",\n                        fullName(report.getApprover()), outcome, report.getId())\n        );\n        mailService.sendMail(mail);\n    }\n\n    @Transactional\n    protected BigDecimal getTotalAmount(Report report) {\n        // Since the report passed to this method is not attached to the JPA session anymore we have to reload it to get\n        // the expenses which are lazily fetched.\n        List<TravelExpense> expenses = travelExpenseReportRepository.findOne(report.getId()).getExpenses();\n        return expenses.stream()\n                .map(TravelExpense::getCost)\n                .reduce(BigDecimal.ZERO, BigDecimal::add);\n    }\n\n    protected String fullName(Employee employee) {\n        return employee.getFirstName() + \" \" + employee.getLastName();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportRepository.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.List;\n\n@RepositoryRestResource(path = \"travelExpenseReports\")\npublic interface ReportRepository extends CrudRepository<Report, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    Iterable<Report> findAll();\n\n    @Override\n    @PostAuthorize(\"hasRole('ROLE_SUPERVISOR') or returnObject?.employee?.email == principal?.username\")\n    Report findOne(Long aLong);\n\n    @PreAuthorize(\"#employee.email == principal?.username\")\n    Page<Report> findByEmployeeAndStatusOrderByStatusAsc(@Param(\"employee\") Employee employee, @Param(\"status\") Report.Status status, Pageable pageable);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    Page<Report> findByStatus(@Param(\"status\") Report.Status status, Pageable pageable);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    List<Report> findBySubmissionDateBetween(@Param(\"start\") Date start, @Param(\"end\") Date end);\n}\n\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/ReportService.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.Date;\n\n@Transactional\npublic class ReportService {\n\n    @Autowired\n    private ReportRepository travelExpenseReportRepository;\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private ReportNotifyService travelExpenseReportNotifyService;\n\n    @PreAuthorize(\"#travelExpenseReport.employee.email == principal?.username\")\n    public Report submit(Report travelExpenseReport) {\n        travelExpenseReportNotifyService.notifySupervisorsOnSubmission(travelExpenseReport);\n        return setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.SUBMITTED, null);\n    }\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.employee.email != principal?.username\")\n    public Report accept(Report travelExpenseReport, String approverName) {\n        Report acceptedReport = setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.APPROVED, approverName);\n        travelExpenseReportNotifyService.notifyEmployeeOnApproval(acceptedReport);\n        return acceptedReport;\n    }\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') and #travelExpenseReport.employee.email != principal?.username\")\n    public Report reject(Report travelExpenseReport, String rejecterName) {\n        Report rejectedReport = setStatusOnTravelExpenseReport(travelExpenseReport, Report.Status.REJECTED, rejecterName);\n        travelExpenseReportNotifyService.notifyEmployeeOnRejection(rejectedReport);\n        return rejectedReport;\n    }\n\n    private Report setStatusOnTravelExpenseReport(Report travelExpenseReport, Report.Status status, String approverName) {\n        if (status == Report.Status.SUBMITTED) {\n            travelExpenseReport.setSubmissionDate(new Date());\n        } else {\n            Employee approver = employeeRepository.findByEmail(approverName);\n            travelExpenseReport.setApprover(approver);\n            travelExpenseReport.setApprovalDate(new Date());\n        }\n        travelExpenseReport.setStatus(status);\n        return travelExpenseReportRepository.save(travelExpenseReport);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/Comment.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@Table(name = \"travelExpenseReportComment\")\npublic class Comment {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @NotEmpty\n    private String text;\n\n    @NotNull\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date submissionDate;\n\n    @ManyToOne\n    @NotNull\n    private Report travelExpenseReport;\n\n    @ManyToOne\n    @NotNull\n    private Employee employee;\n}\n\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\n\n@RepositoryEventHandler(value = Comment.class)\n@SuppressWarnings(\"unused\")\npublic class CommentEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #comment.employee.email == principal?.username\")\n    public void checkCreateAuthority(Comment comment) {\n        comment.setSubmissionDate(new Date());\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"denyAll()\")\n    public void checkUpdateAuthority(Comment comment) {\n        //deny all\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkSaveAuthority(Comment comment, Object links) {\n        //deny all\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkDeleteAuthority(Comment comment, Object linkedEntity) {\n        //deny all\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentRepository.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.List;\n\n@RepositoryRestResource(path = \"travelExpenseReportComments\")\npublic interface CommentRepository extends CrudRepository<Comment, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    Iterable<Comment> findAll();\n\n    @Override\n    @RestResource(exported = false)\n    Comment findOne(Long aLong);\n\n    @Override\n    @RestResource(exported = false)\n    void delete(Long aLong);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #travelExpenseReport.employee.email == principal?.username\")\n    List<Comment> findByTravelExpenseReportOrderBySubmissionDateAsc(@Param(\"report\") Report travelExpenseReport);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/expenses/reports/comments/CommentWithEmployeeProjection.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.reports.comments;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = Comment.class, name = \"withEmployee\")\npublic interface CommentWithEmployeeProjection {\n    Long getId();\n\n    String getText();\n\n    Date getSubmissionDate();\n\n    Employee getEmployee();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/login/PrincipalController.java",
    "content": "package de.techdev.trackr.domain.employee.login;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport de.techdev.trackr.domain.employee.Settings;\nimport de.techdev.trackr.domain.employee.SettingsRepository;\nimport lombok.Getter;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.security.Principal;\nimport java.util.Collection;\n\n@Controller\n@Slf4j\npublic class PrincipalController {\n\n    @Getter\n    @Setter\n    static class ReturnValue {\n        Collection<? extends GrantedAuthority> authorities;\n        String locale;\n        Long id;\n        String email;\n    }\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private SettingsRepository settingsRepository;\n\n    @RequestMapping(value = \"/principal\", produces = MediaType.APPLICATION_JSON_VALUE)\n    @ResponseBody\n    public ReturnValue principal(Principal principal) {\n        if (principal != null) {\n            Employee employee = employeeRepository.findByEmail(principal.getName());\n            if (employee != null) {\n                Settings localeSettings = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, employee.getEmail());\n                ReturnValue value = new ReturnValue();\n                value.locale = localeSettings.getValue();\n                value.id = employee.getId();\n                value.authorities = ((Authentication) principal).getAuthorities();\n                value.email = principal.getName();\n                return value;\n            } else {\n                log.error(\"Somehow someone with an invalid email is in our system: {}\", principal.getName());\n                throw new IllegalStateException(\"Invalid email address in principal.\");\n            }\n        } else {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/login/support/SupervisorService.java",
    "content": "package de.techdev.trackr.domain.employee.login.support;\n\nimport de.techdev.trackr.core.security.AuthorityService;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.Collection;\nimport java.util.function.Predicate;\n\npublic class SupervisorService {\n\n    @Autowired\n    private AuthorityService authorityService;\n\n    /**\n     * @return Email addresses of all supervisors\n     */\n    public String[] getSupervisorEmailsAsArray() {\n        return getSupervisorEmailsArrayWithout(c -> true);\n    }\n\n    /**\n     * @param withoutThese A predicate to filter out supervisors, e.g. the logged in principal.\n     * @return Email addresses of all supervisors for whose credentials the predicate returns true.\n     */\n    public String[] getSupervisorEmailsArrayWithout(Predicate<String> withoutThese) {\n        Collection<String> supervisor = authorityService.getEmployeeEmailsByAuthority(\"ROLE_SUPERVISOR\");\n        return supervisor.stream().filter(withoutThese).toArray(String[]::new);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDays.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@EndAfterBegin(begin = \"startDate\", end = \"endDate\")\npublic class SickDays {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @ManyToOne\n    @NotNull\n    private Employee employee;\n\n    @Temporal(TemporalType.DATE)\n    @NotNull\n    private Date startDate;\n\n    @Temporal(TemporalType.DATE)\n    private Date endDate;\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n@RepositoryEventHandler(value = SickDays.class)\n@SuppressWarnings(\"unused\")\npublic class SickDaysEventHandler {\n\n    @Autowired\n    private SickDaysNotifyService sickDaysNotifyService;\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"#sickDays.employee.email == principal?.username or hasRole('ROLE_ADMIN')\")\n    public void checkSaveAuthority(SickDays sickDays) {\n        sickDaysNotifyService.notifySupervisorsAboutNew(sickDays);\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"#sickDays.employee.email == principal?.username or hasRole('ROLE_ADMIN')\")\n    public void checkUpdateAuthority(SickDays sickDays) {\n        sickDaysNotifyService.notifySupervisorsAboutUpdate(sickDays);\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkDeleteAuthority(SickDays sickDays) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkUpdateAuthority(SickDays sickDays, Object links) {\n        //deny all\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkSaveAuthority(SickDays sickDays, Object linkedEntity) {\n        //deny all\n    }\n}\n\n\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysNotifyService.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.trackr.domain.employee.login.support.SupervisorService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.mail.SimpleMailMessage;\n\nimport java.text.SimpleDateFormat;\n\n/**\n * @author Moritz Schulze\n */\npublic class SickDaysNotifyService {\n\n    @Autowired\n    private MailService mailService;\n\n    @Autowired\n    private SupervisorService supervisorService;\n\n    public void notifySupervisorsAboutNew(SickDays sickDays) {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"dd.MM.yyyy\");\n        String subject = \"Sick days reported by \" + sickDays.getEmployee().fullName();\n        String text = sickDays.getEmployee().fullName() + \" reported sick days from \" + sdf.format(sickDays.getStartDate())\n                + \" to \" + (sickDays.getEndDate() != null ? sdf.format(sickDays.getEndDate()) : \" (not set)\" ) + \".\";\n        notifySupervisors(subject, text);\n    }\n\n    public void notifySupervisorsAboutUpdate(SickDays sickDays) {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"dd.MM.yyyy\");\n        String subject = \"Sick days updated by \" + sickDays.getEmployee().fullName();\n        String text = sickDays.getEmployee().fullName() + \" updated his sick days. Interval is now from \" + sdf.format(sickDays.getStartDate())\n                + \" to \" + (sickDays.getEndDate() != null ? sdf.format(sickDays.getEndDate()) : \" (not set)\") + \".\";\n        notifySupervisors(subject, text);\n    }\n\n    protected void notifySupervisors(String subject, String text) {\n        String[] receiver = supervisorService.getSupervisorEmailsAsArray();\n        SimpleMailMessage mailMessage = new SimpleMailMessage();\n        mailMessage.setSubject(subject);\n        mailMessage.setTo(receiver);\n        mailMessage.setText(text);\n        mailMessage.setFrom(\"no-reply@techdev.de\");\n        mailService.sendMail(mailMessage);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysRepository.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RepositoryRestResource;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.List;\n\n@RepositoryRestResource(path = \"sickDays\")\npublic interface SickDaysRepository extends JpaRepository<SickDays, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    Page<SickDays> findAll(Pageable pageable);\n\n    @Override\n    @PostAuthorize(\"hasRole('ROLE_ADMIN') or principal?.username == returnObject.employee.email\")\n    SickDays findOne(Long aLong);\n\n    @PreAuthorize(\"#employee.email == principal?.username\")\n    List<SickDays> findByEmployee(@Param(\"employee\") Employee employee);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    List<SickDays> findByStartDateBetweenOrEndDateBetween(\n            @Param(\"startLower\") Date startLower,\n            @Param(\"startHigher\") Date startHigher,\n            @Param(\"endLower\") Date endLower,\n            @Param(\"endHigher\") Date endHigher\n    );\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/sickdays/SickDaysWithEmployeeProjection.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = SickDays.class, name = \"withEmployee\")\npublic interface SickDaysWithEmployeeProjection {\n    Long getId();\n\n    Integer getVersion();\n\n    Employee getEmployee();\n\n    Date getStartDate();\n\n    Date getEndDate();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/Holiday.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\npublic class Holiday {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Temporal(TemporalType.DATE)\n    private Date day;\n\n    private String name;\n\n    @Enumerated(EnumType.STRING)\n    private FederalState federalState;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculator.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.time.DayOfWeek;\nimport java.time.LocalDate;\nimport java.util.Date;\nimport java.util.List;\n\nimport static java.util.stream.Collectors.toList;\n\n/**\n * @author Moritz Schulze\n */\npublic class HolidayCalculator {\n\n    @Autowired\n    private HolidayRepository holidayRepository;\n\n    public Integer calculateDifferenceBetweenExcludingHolidaysAndWeekends(Date start, Date end, FederalState federalState) {\n        List<Holiday> holidays = holidayRepository.findByFederalStateAndDayBetween(federalState, start, end);\n        return calculateDifferenceBetweenExcludingHolidaysAndWeekends(LocalDateUtil.fromDate(start), LocalDateUtil.fromDate(end), holidays.stream()\n                                                                                                      .map(holiday -> LocalDateUtil.fromDate(holiday.getDay()))\n                                                                                                      .collect(toList()));\n    }\n\n    protected Integer calculateDifferenceBetweenExcludingHolidaysAndWeekends(LocalDate start, LocalDate end, List<LocalDate> holidays) {\n        LocalDate step = start;\n        Integer count = 0;\n        while(step.isBefore(end.plusDays(1))) {\n            if(!isWeekendOrHoliday(step, holidays)) {\n                count++;\n            }\n            step = step.plusDays(1);\n        }\n        return count;\n    }\n\n    /**\n     * Checks whether a date is a weekend day or in a given list of holidays.\n     *\n     * @param date The date to check\n     * @param holidays A list of dates that are seens as holidays\n     * @return True if the date is a sunday or saturday or in the list.\n     */\n    protected boolean isWeekendOrHoliday(LocalDate date, List<LocalDate> holidays) {\n        return date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY || holidays.stream().anyMatch(date::equals);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/HolidayRepository.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic interface HolidayRepository extends CrudRepository<Holiday, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    <S extends Holiday> S save(S entity);\n\n    @Override\n    @RestResource(exported = false)\n    void delete(Long id);\n\n    List<Holiday> findByFederalStateAndDayBetween(@Param(\"state\") FederalState federalState, @Param(\"start\") Date start, @Param(\"end\") Date end);\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@EndAfterBegin(begin = \"startDate\", end = \"endDate\")\npublic class VacationRequest {\n\n    public enum VacationRequestStatus {\n        APPROVED, PENDING, REJECTED\n    }\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @ManyToOne\n    @NotNull\n    private Employee employee;\n\n    @Temporal(TemporalType.DATE)\n    @NotNull\n    private Date startDate;\n\n    @Temporal(TemporalType.DATE)\n    @NotNull\n    private Date endDate;\n\n    private Integer numberOfDays;\n\n    @Enumerated(EnumType.STRING)\n    private VacationRequestStatus status;\n\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date approvalDate;\n\n    @Temporal(TemporalType.TIMESTAMP)\n    private Date submissionTime;\n\n    @ManyToOne\n    private Employee approver;\n\n    @JsonIgnore\n    public boolean isApproved() {\n        return status == VacationRequestStatus.APPROVED;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestApproveService.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.time.LocalDate;\nimport java.util.Date;\nimport java.util.List;\n\n@Slf4j\npublic class VacationRequestApproveService {\n\n    @Autowired\n    private VacationRequestRepository vacationRequestRepository;\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private VacationRequestNotifyService vacationRequestNotifyService;\n\n    @Autowired\n    private UuidMapper uuidMapper;\n\n    @Transactional\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email\")\n    public VacationRequest approve(VacationRequest vacationRequest, String supervisorEmail) {\n        return setStatusOnVacationRequest(vacationRequest, supervisorEmail, VacationRequest.VacationRequestStatus.APPROVED);\n    }\n\n    /**\n     * Rejects a vacation request. The vacation request will be fetched from the repository, the rejector by the name given in\n     * supervisor email.\n     * <p>\n     * Will only reject pending vacation requests.\n     *\n     * @param vacationRequest   The vacation request to reject.\n     * @param supervisorEmail   The email address of the employee to use as the approver.\n     * @return The approved (or not) vacation request.\n     */\n    @Transactional\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email\")\n    public VacationRequest reject(VacationRequest vacationRequest, String supervisorEmail) {\n        return setStatusOnVacationRequest(vacationRequest, supervisorEmail, VacationRequest.VacationRequestStatus.REJECTED);\n    }\n\n    /**\n     * Approves all requests that are more than seven days old.\n     */\n    @Transactional\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void approveSevenDayOldRequests() {\n        LocalDate oneWeekAgo = LocalDate.now().minusDays(7);\n        List<VacationRequest> vacationRequests = vacationRequestRepository.findBySubmissionTimeBeforeAndStatus(LocalDateUtil.fromLocalDate(oneWeekAgo), VacationRequest.VacationRequestStatus.PENDING);\n        vacationRequests.forEach(vacationRequest -> {\n            log.info(\"Approving more then seven days old vacation request {}\", vacationRequest);\n            approve(vacationRequest, null);\n        });\n    }\n\n    protected VacationRequest setStatusOnVacationRequest(VacationRequest vacationRequest, String supervisorEmail, VacationRequest.VacationRequestStatus status) {\n        if (vacationRequest.getStatus() == VacationRequest.VacationRequestStatus.PENDING) {\n            Employee supervisor = null;\n            Employee byEmail = employeeRepository.findByEmail(supervisorEmail);\n            if (byEmail != null) {\n                supervisor = byEmail;\n            }\n            vacationRequest.setStatus(status);\n            vacationRequest.setApprover(supervisor);\n            vacationRequest.setApprovalDate(new Date());\n            vacationRequest = vacationRequestRepository.save(vacationRequest);\n\n            vacationRequestNotifyService.sendEmailNotification(vacationRequest);\n        }\n        uuidMapper.deleteUUID(vacationRequest.getId());\n        return vacationRequest;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestController.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.vacation.support.VacationRequestEmployeeToDaysTotalService;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\nimport java.security.Principal;\nimport java.util.Date;\nimport java.util.Map;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/vacationRequests\")\n@Slf4j\npublic class VacationRequestController {\n\n    @Autowired\n    private VacationRequestApproveService vacationRequestApproveService;\n\n    @Autowired\n    private VacationRequestEmployeeToDaysTotalService vacationRequestEmployeeToDaysTotalService;\n\n    /**\n     * Approve a vacation request. Can only be done by supervisors, but they are not allowed to approve their own requests.\n     * Only works on pending requests.\n     *\n     * @param vacationRequest The vacation request to approve\n     * @param principal       The Spring Security principal to extract the user from.\n     * @return The vacation request object.\n     */\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    @RequestMapping(value = \"/{id}/approve\", method = RequestMethod.PUT)\n    @ResponseStatus(HttpStatus.OK)\n    @ResponseBody\n    public VacationRequest approve(@PathVariable(\"id\") VacationRequest vacationRequest, Principal principal) {\n        return vacationRequestApproveService.approve(vacationRequest, principal.getName());\n    }\n\n    /**\n     * Reject a vacation request. Can only be done by supervisors, but they are not allowed to reject their own requests.\n     * Only works on pending requests.\n     *\n     * @param vacationRequest The vacation request to reject.\n     * @param principal       The Spring Security principal to extract the user from.\n     * @return The vacation request object.\n     */\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    @RequestMapping(value = \"/{id}/reject\", method = RequestMethod.PUT)\n    @ResponseStatus(HttpStatus.OK)\n    @ResponseBody\n    public VacationRequest reject(@PathVariable(\"id\") VacationRequest vacationRequest, Principal principal) {\n        return vacationRequestApproveService.reject(vacationRequest, principal.getName());\n    }\n\n    /**\n     * Create a mapping of employee names to the effective number of vacation days between a start and end date.\n     *\n     * 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.\n     * Public holidays and weekends are excluded.\n     */\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    @ResponseBody\n    @RequestMapping(value = \"/daysPerEmployeeBetween\", method = RequestMethod.GET, produces = \"application/hal+json\")\n    @ResponseStatus(HttpStatus.OK)\n    public Map<String, Integer> daysPerEmployeeBetween(\n            @RequestParam(\"start\") Date start,\n            @RequestParam(\"end\") Date end\n    ) {\n        return vacationRequestEmployeeToDaysTotalService.mapVacationRequestsToTotalDays(start, end);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestEventHandler.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techdev.trackr.domain.employee.vacation.support.VacationRequestNotifyService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.UUID;\n\n@RepositoryEventHandler(VacationRequest.class)\n@SuppressWarnings(\"unused\")\npublic class VacationRequestEventHandler {\n\n    @Autowired\n    private HolidayCalculator holidayCalculator;\n\n    @Autowired\n    private VacationRequestNotifyService vacationRequestNotifyService;\n\n    @Autowired\n    private UuidMapper uuidMapper;\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN') or principal?.username == #vacationRequest.employee.email\")\n    public void prepareVacationRequest(VacationRequest vacationRequest) {\n        Integer difference = holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(vacationRequest.getStartDate(),\n                vacationRequest.getEndDate(),\n                vacationRequest.getEmployee().getFederalState());\n        vacationRequest.setNumberOfDays(difference);\n        vacationRequest.setStatus(VacationRequest.VacationRequestStatus.PENDING);\n        vacationRequest.setApprover(null);\n        vacationRequest.setApprovalDate(null);\n        vacationRequest.setSubmissionTime(new Date());\n    }\n\n    @HandleAfterCreate\n    public void afterCreation(VacationRequest vacationRequest) {\n        UUID uuid = uuidMapper.createUUID(vacationRequest.getId());\n        vacationRequestNotifyService.notifySupervisors(vacationRequest, uuid);\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') and principal?.username != #vacationRequest.employee.email\")\n    public void authorizeUpdate(VacationRequest vacationRequest) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"( hasRole('ROLE_SUPERVISOR') and @vacationRequestEventHandler.supervisorCanDeleteRequest(principal?.username, #vacationRequest) ) \" +\n            \"or @vacationRequestEventHandler.employeeCanDeleteRequest(principal?.username, #vacationRequest)\")\n    public void authorizeDelete(VacationRequest vacationRequest) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"denyAll()\")\n    public void denyLinksSave(VacationRequest vacationRequest, Object links) {\n        //deny all, cannot be called\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void denyLinks(VacationRequest vacationRequest, Object linkedEntity) {\n        //deny all, cannot be called\n    }\n\n    /**\n     * Test if an employee may delete a vacation request. This means it is his own request and it is pending.\n     * @param username The email of the logged in user\n     * @param request The vacation request\n     * @return true if the user may delete, false otherwise.\n     */\n    public boolean employeeCanDeleteRequest(String username, VacationRequest request) {\n        return username != null &&\n                username.equals(request.getEmployee().getEmail()) && request.getStatus() == VacationRequest.VacationRequestStatus.PENDING;\n    }\n\n    public boolean supervisorCanDeleteRequest(String username, VacationRequest request) {\n        return username != null &&\n                !username.equals(request.getEmployee().getEmail());\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepository.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.List;\n\npublic interface VacationRequestRepository extends CrudRepository<VacationRequest, Long> {\n\n    @Override\n    @PostAuthorize(\"hasRole('ROLE_SUPERVISOR') or principal?.username == returnObject.employee.email\")\n    VacationRequest findOne(Long aLong);\n\n    @Override\n    @RestResource(exported = false)\n    Iterable<VacationRequest> findAll();\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or principal?.username == #employee.email\")\n    List<VacationRequest> findByEmployeeOrderByStartDateAsc(@Param(\"employee\") Employee employee);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<VacationRequest> findByStatusOrderBySubmissionTimeAsc(@Param(\"status\") VacationRequest.VacationRequestStatus status);\n\n    @RestResource(exported = false)\n    List<VacationRequest> findBySubmissionTimeBeforeAndStatus(Date date, VacationRequest.VacationRequestStatus status);\n\n    /**\n     * Find vacation requests of a certain status that overlap with a period.\n     */\n    @RestResource(exported = false)\n    @Query(\"SELECT vr FROM VacationRequest vr WHERE (vr.startDate BETWEEN :startLower AND :startHigher OR vr.endDate BETWEEN :endLower AND :endHigher) AND vr.status = :status\")\n    List<VacationRequest> findByStartDateBetweenOrEndDateBetweenAndStatus(\n            @Param(\"startLower\") Date startLower, @Param(\"startHigher\") Date startHigher,\n            @Param(\"endLower\") Date endLower, @Param(\"endHigher\") Date endHigher,\n            @Param(\"status\") VacationRequest.VacationRequestStatus status);\n\n    /**\n     * Find one by id without security.\n     * @param id The id of the vacation request to find.\n     */\n    @RestResource(exported = false)\n    @Query(\"SELECT vr FROM VacationRequest vr WHERE vr.id = :id\")\n    VacationRequest findOneWithoutSecurity(@Param(\"id\") Long id);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobs.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.scheduling.annotation.Scheduled;\n\n/**\n * @author Moritz Schulze\n */\n@Slf4j\npublic class VacationRequestScheduledJobs {\n\n    @Autowired\n    private VacationRequestApproveService vacationRequestApproveService;\n\n    @Scheduled(cron = \"0 0 4 * * *\")\n    public void approveSevenDaysOldVacationRequests() {\n        log.debug(\"Executing vacation request approval trigger.\");\n        vacationRequestApproveService.approveSevenDayOldRequests();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/VacationRequestWithEmployeeAndApproverProjection.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = VacationRequest.class, name = \"withEmployeeAndApprover\")\npublic interface VacationRequestWithEmployeeAndApproverProjection {\n    Long getId();\n\n    Employee getEmployee();\n\n    Date getStartDate();\n\n    Date getEndDate();\n\n    Integer getNumberOfDays();\n\n    VacationRequest.VacationRequestStatus getStatus();\n\n    Date getApprovalDate();\n\n    Date getSubmissionTime();\n\n    Employee getApprover();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveService.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.common.UuidMapper;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequestApproveService;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequestRepository;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.stereotype.Service;\nimport org.springframework.util.StringUtils;\n\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport java.io.IOException;\n\n@Slf4j\n@Service\n@Profile(\"gmail\")\npublic class MailApproveService {\n\n    @Autowired\n    private UuidMapper uuidMapper;\n\n    @Autowired\n    private VacationRequestRepository vacationRequestRepository;\n\n    @Autowired\n    private VacationRequestApproveService vacationRequestApproveService;\n\n    public void approveOrRejectFromMail(Message mail) {\n        log.debug(\"Got mail.\");\n        String subject;\n        String content;\n        String from;\n        MessageWrapper message = new MessageWrapper(mail);\n        try {\n            subject = mail.getSubject();\n            content = message.extractContentAsString();\n            from = message.getSender();\n        } catch (MessagingException | IOException e) {\n            throw new RuntimeException(\"Could not extract uuid or content from the mail.\", e);\n        }\n        String uuid = uuidMapper.extractUUIDFromString(subject);\n\n        if (uuid == null) {\n            throw new RuntimeException(\"Could find a UUID in the subject \" + subject);\n        }\n        log.debug(\"Extracted UUID {} from subject.\" , uuid);\n        Long id = uuidMapper.getIdFromUUID(uuid);\n\n        if (id != null) {\n            log.debug(\"Got ID {} from the mapper.\", id);\n            actualApprove(id, from, content);\n        } else {\n            log.debug(\"Did not find an ID for UUID {}, deleting record.\", uuid);\n            uuidMapper.deleteUUID(uuid);\n        }\n    }\n\n    /**\n     * Analyze the text of a mail and decide if the vacation request should be approved or rejected.\n     * If the word \"approve\" appears more often approve, if the word \"reject\" appears more often reject. If\n     * they appear with the same number, throw an {@link java.lang.IllegalArgumentException}.\n     * @param mailContent The content of the mail.\n     * @return The status APPROVED when to approve and the status REJECTED when to reject.\n     */\n    protected VacationRequest.VacationRequestStatus approveOrReject(String mailContent) {\n        String mailContentLowerCase = mailContent.toLowerCase();\n\n        int approveCount = StringUtils.countOccurrencesOf(mailContentLowerCase, \"approve\");\n        int rejectCount = StringUtils.countOccurrencesOf(mailContentLowerCase, \"reject\");\n        if (approveCount > rejectCount) {\n            return VacationRequest.VacationRequestStatus.APPROVED;\n        } else if (approveCount < rejectCount) {\n            return VacationRequest.VacationRequestStatus.REJECTED;\n        } else {\n            throw new IllegalStateException(\"Cannot decide from the text if to approve or reject\");\n        }\n    }\n\n    protected void actualApprove(Long vacationRequestId, String supervisorEmail, String content) {\n        VacationRequest vacationRequest = vacationRequestRepository.findOneWithoutSecurity(vacationRequestId);\n        if (vacationRequest == null) {\n            log.debug(\"Did not find a vacation request for id {}.\", vacationRequestId);\n            return;\n        }\n\n        if (vacationRequest.getEmployee().getEmail().equals(supervisorEmail)) {\n            log.warn(\"Supervisor {} tried to approve his/her own vacation request via mail.\", supervisorEmail);\n            return;\n        }\n\n        VacationRequest.VacationRequestStatus status = approveOrReject(content);\n        if (status == VacationRequest.VacationRequestStatus.APPROVED) {\n            vacationRequestApproveService.approve(vacationRequest, supervisorEmail);\n        } else if (status == VacationRequest.VacationRequestStatus.REJECTED) {\n            vacationRequestApproveService.reject(vacationRequest, supervisorEmail);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapper.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport javax.mail.Address;\nimport javax.mail.Message;\nimport javax.mail.MessagingException;\nimport javax.mail.Multipart;\nimport javax.mail.internet.InternetAddress;\nimport javax.mail.internet.MimeMultipart;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nclass MessageWrapper {\n\n    private final Message message;\n\n    public MessageWrapper(Message message) {\n        this.message = message;\n    }\n\n    /**\n     * Extract the content of a Mail as a String depending on the content type.\n     * text/plain -> directly\n     * multipart/mime -> only the text/plain part if it exists, null otherwise\n     * multipart -> the body\n     * @return\n     * @throws IOException\n     * @throws MessagingException\n     */\n     String extractContentAsString() throws IOException, MessagingException {\n        Object content = message.getContent();\n        if (content instanceof String) {\n            return (String) content;\n        }\n        if(content instanceof MimeMultipart) {\n            MimeMultipart multipart = (MimeMultipart) content;\n            for (int i = 0; i < multipart.getCount(); i++) {\n                if (multipart.getBodyPart(i).getContentType().startsWith(\"text/plain\")) {\n                    return (String)multipart.getBodyPart(i).getContent();\n                }\n            }\n            return null;\n        }\n        if (content instanceof Multipart) {\n            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n            ((Multipart) content).writeTo(outputStream);\n            return new String(outputStream.toByteArray(), \"UTF-8\");\n        }\n        throw new IllegalArgumentException(\"Incompatible message type.\");\n    }\n\n    /**\n     * Extracts the sender of an email if it is an InternetAddress.\n     * @return The address or null if it's not a techdev address.\n     * @throws MessagingException\n     */\n    String getSender() throws MessagingException {\n        String from = null;\n        Address[] fromArray = message.getFrom();\n        if (fromArray.length > 0) {\n            Address address = message.getFrom()[0];\n            if (address instanceof InternetAddress) {\n                from = ((InternetAddress) address).getAddress();\n                if (!from.endsWith(\"techdev.de\")) {\n                    from = null;\n                }\n            }\n        }\n        return from;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalService.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.employee.vacation.HolidayCalculator;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequestRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.ToIntFunction;\nimport java.util.stream.Collectors;\n\n/**\n * @author Moritz Schulze\n */\npublic class VacationRequestEmployeeToDaysTotalService {\n\n    @Autowired\n    private HolidayCalculator holidayCalculator;\n\n    @Autowired\n    private VacationRequestRepository vacationRequestRepository;\n\n    /**\n     * Groups vacation requests by their employee (the full name to be precise) and sums up all _actual_ vacation days between start and\n     * end for all vacation requests of that employee.\n     * @param start The start of the period\n     * @param end The end of the period\n     * @return A map of employee names to days of vacation in between start and end.\n     */\n    public Map<String, Integer> mapVacationRequestsToTotalDays(Date start, Date end) {\n        List<VacationRequest> vacationRequests = vacationRequestRepository\n                .findByStartDateBetweenOrEndDateBetweenAndStatus(start, end, start, end, VacationRequest.VacationRequestStatus.APPROVED);\n        return mapToEmployeesAndSumUp(vacationRequests, vacationRequest -> getVacationDaysBetween(vacationRequest, start, end));\n    }\n\n    /**\n     * Groups vacation requests by employee names and adds for every vacation request the numbers returned by the mapper.\n     * @param vacationRequests The vacation requests to group\n     * @param numberExtractor A function that maps a vacation request to a number.\n     * @return A map of the employee names to the sum of numbers returned by the mapper for their vacation requests.\n     */\n    protected Map<String, Integer> mapToEmployeesAndSumUp(List<VacationRequest> vacationRequests, ToIntFunction<VacationRequest> numberExtractor) {\n        return vacationRequests.stream().collect(\n                Collectors.groupingBy(\n                        vacationRequest -> vacationRequest.getEmployee().getFirstName() + \" \" + vacationRequest.getEmployee().getLastName(),\n                        Collectors.summingInt(numberExtractor)\n                )\n        );\n    }\n\n    /**\n     * @return Returns the number of days of the vacation request between start and end that aren't holidays or weekends.\n     */\n    protected Integer getVacationDaysBetween(VacationRequest vacationRequest, Date start, Date end) {\n        return holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(\n                // If the start of the vacation request is before the desired period we use the period start\n                getMaximum(start, vacationRequest.getStartDate()),\n                // If the end of the vacation request is after the desired period we use the period end\n                getMinimum(end, vacationRequest.getEndDate()),\n                vacationRequest.getEmployee().getFederalState()\n        );\n    }\n\n    /**\n     * The minimum of the two dates. No null checks.\n     */\n    protected Date getMinimum(Date a, Date b) {\n        return a.before(b) ? a : b;\n    }\n\n    /**\n     * The maximum of the two dates. No null checks.\n     */\n    protected Date getMaximum(Date a, Date b) {\n        return a.before(b) ? b : a;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyService.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.trackr.domain.employee.login.support.SupervisorService;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.mail.SimpleMailMessage;\n\nimport java.text.SimpleDateFormat;\nimport java.util.UUID;\n\npublic class VacationRequestNotifyService {\n\n    @Autowired\n    private MailService mailService;\n\n    @Autowired\n    private SupervisorService supervisorService;\n\n    /**\n     * Sends an approval or rejection mail depending on the status of the parameter.\n     * @param request The request for which the mail is to sent.\n     */\n    public void sendEmailNotification(VacationRequest request) {\n        SimpleMailMessage mailMessage = new SimpleMailMessage();\n        mailMessage.setFrom(\"no-reply@techdev.de\");\n        mailMessage.setTo(request.getEmployee().getEmail());\n        mailMessage.setSubject(\"Your vacation request has been \" + statusPastVerb(request.getStatus()));\n        mailMessage.setText(getStatusMailText(request));\n        mailService.sendMail(mailMessage);\n    }\n\n    protected String statusPastVerb(VacationRequest.VacationRequestStatus status) {\n        if(status == VacationRequest.VacationRequestStatus.APPROVED) {\n            return \"approved\";\n        } else if (status == VacationRequest.VacationRequestStatus.REJECTED) {\n            return \"rejected\";\n        } else {\n            return \"is pending\";\n        }\n    }\n\n    protected String getStatusMailText(VacationRequest request) {\n        if(request.getApprover() == null) {\n            return \"Your vacation request has been automatically approved.\";\n        } else {\n            return request.getApprover().fullName() + \" has \" + statusPastVerb(request.getStatus()) + \" your vacation request from \" + request.getSubmissionTime();\n        }\n    }\n\n    /**\n     * Send a new vacation request notification to all supervisors.\n     */\n    public void notifySupervisors(VacationRequest vacationRequest, UUID uuid) {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"dd.MM.yyyy\");\n        String[] receiver = supervisorService.getSupervisorEmailsAsArray();\n        SimpleMailMessage mailMessage = new SimpleMailMessage();\n        String subject = \"New vacation request from \" + vacationRequest.getEmployee().fullName() + \"; \" + uuid.toString();\n        String text = \"New vacation request from \" + vacationRequest.getEmployee().fullName() + \" for \" + sdf.format(vacationRequest.getStartDate()) + \" - \" + sdf\n                .format(vacationRequest.getEndDate()) + \". You can reply to this email with approve or reject to do that.\";\n        mailMessage.setSubject(subject);\n        mailMessage.setTo(receiver);\n        mailMessage.setText(text);\n        mailMessage.setFrom(\"no-reply@techdev.de\");\n        mailService.sendMail(mailMessage);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderService.java",
    "content": "package de.techdev.trackr.domain.employee.worktimetracking;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.mail.SimpleMailMessage;\n\nimport java.util.List;\n\n/**\n * Remind employees to track their working times.\n */\npublic class WorkTimeTrackingReminderService {\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private MailService mailService;\n\n    @Value(\"${trackr.frontendUrl}\")\n    private String frontendUrl;\n\n    /**\n     * Remind all employees of a federal state to track their working times via mail. Since holidays differ in different states this needs the state.\n     * @param state The federal state to select employees from.\n     */\n    public void remindEmployeesToTrackWorkTimes(FederalState state) {\n        List<Employee> allEmployees = employeeRepository.findByFederalState(state);\n        allEmployees.forEach(employee -> {\n            SimpleMailMessage mailMessage = getReminderMailMessage(employee);\n            mailService.sendMail(mailMessage);\n        });\n    }\n\n    protected SimpleMailMessage getReminderMailMessage(Employee employee) {\n        SimpleMailMessage mailMessage = new SimpleMailMessage();\n        mailMessage.setTo(employee.getEmail());\n        mailMessage.setFrom(\"no-reply@techdev.de\");\n        mailMessage.setSubject(\"Track your working time\");\n        mailMessage.setText(\"Please make sure to track your working time by the end of the month: \" + frontendUrl + \"/employee/timesheet\");\n        return mailMessage;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/Project.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.domain.project.billtimes.BillableTime;\nimport de.techdev.trackr.domain.project.worktimes.WorkTime;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.Min;\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@JsonIgnoreProperties({\"workTimes\", \"billableTimes\"})\npublic class Project {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotEmpty\n    @Column(unique = true)\n    private String identifier;\n\n    @NotEmpty\n    private String name;\n\n    @ManyToOne\n    @JoinColumn(name = \"company_id\")\n    private Company company;\n\n    @Min(0)\n    private Integer volume;\n\n    @Min(0)\n    private BigDecimal hourlyRate;\n\n    @Min(0)\n    private BigDecimal dailyRate;\n\n    @Min(0)\n    private BigDecimal fixedPrice;\n\n    @ManyToOne\n    @JoinColumn(name = \"debitor_id\")\n    private Company debitor;\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"project\")\n    private List<WorkTime> workTimes = new ArrayList<>();\n\n    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = \"project\")\n    private List<BillableTime> billableTimes = new ArrayList<>();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/ProjectEventHandler.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(Project.class)\n@SuppressWarnings(\"unused\")\npublic class ProjectEventHandler {\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkUpdatePermission(Project project) {\n    }\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkCreatePermission(Project project) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkDeletePermission(Project project) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkCompanyPermission(Project project, Object link) {\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void checkLinkDeletePermission(Project project, Object linkedEntity) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/ProjectRepository.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.repository.query.Param;\n\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic interface ProjectRepository extends JpaRepository<Project, Long> {\n\n    Project findByIdentifier(@Param(\"identifier\") String identifier);\n\n    List<Project> findByNameLikeIgnoreCaseOrIdentifierLikeIgnoreCaseOrderByNameAsc(@Param(\"name\") String name, @Param(\"identifier\") String identifier);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/ProjectWithCompanyAndDebitorProjection.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport de.techdev.trackr.domain.company.Company;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.math.BigDecimal;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = Project.class, name = \"withCompanyAndDebitor\")\npublic interface ProjectWithCompanyAndDebitorProjection {\n    Long getId();\n\n    Integer getVersion();\n\n    String getIdentifier();\n\n    String getName();\n\n    Company getCompany();\n\n    Integer getVolume();\n\n    BigDecimal getHourlyRate();\n\n    BigDecimal getDailyRate();\n\n    BigDecimal getFixedPrice();\n\n    Company getDebitor();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTime.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.Project;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.Min;\nimport javax.validation.constraints.NotNull;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@Table(uniqueConstraints = @UniqueConstraint(columnNames = {\"employee\", \"project\", \"date\"}))\npublic class BillableTime {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @ManyToOne\n    @NotNull\n    @JoinColumn(name = \"employee\")\n    private Employee employee;\n\n    @ManyToOne\n    @NotNull\n    @JoinColumn(name = \"project\")\n    private Project project;\n\n    @NotNull\n    @Temporal(TemporalType.DATE)\n    private Date date;\n\n    @NotNull\n    @Min(0)\n    private Integer minutes;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeController.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\nimport static java.util.stream.Collectors.groupingBy;\nimport static java.util.stream.Collectors.summingInt;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/billableTimes\")\npublic class BillableTimeController {\n\n    @Autowired\n    @Qualifier(\"defaultConversionService\")\n    private ConversionService conversionService;\n\n    @Autowired\n    private BillableTimeRepository billableTimeRepository;\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    @ResponseBody\n    @RequestMapping(value = \"/findEmployeeMappingByProjectAndDateBetween\", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    public Map<String, Integer> findEmployeeMappingByProjectAndDateBetween(@RequestParam(\"project\") String projectId,\n                                                           @RequestParam(\"start\") Date start,\n                                                           @RequestParam(\"end\") Date end) {\n        Project project = conversionService.convert(Long.valueOf(projectId), Project.class);\n        List<BillableTime> billableTimes = billableTimeRepository.findByProjectAndDateBetweenOrderByDateAsc(project, start, end);\n        return billableTimes.stream().collect(groupingBy(bt -> bt.getEmployee().fullName(), summingInt(BillableTime::getMinutes)));\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeEventHandler.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(BillableTime.class)\n@SuppressWarnings(\"unused\")\npublic class BillableTimeEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkCreateAuthority(BillableTime billableTime) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkUpdateAuthority(BillableTime billableTime) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkDeleteAuthority(BillableTime billableTime) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    public void checkLinkSaveAuthority(BillableTime billableTime, Object links) {\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void checkLinkDeleteAuthority(BillableTime billableTime, Object linkedEntity) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeRepository.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic interface BillableTimeRepository extends CrudRepository<BillableTime, Long> {\n    @Override\n    @RestResource(exported = false)\n    Iterable<BillableTime> findAll();\n\n    @Override\n    @RestResource(exported = false)\n    Iterable<BillableTime> findAll(Iterable<Long> longs);\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    BillableTime findOne(Long aLong);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<BillableTime> findByProjectAndDateBetweenOrderByDateAsc(@Param(\"project\") Project project,\n                                                                 @Param(\"start\") Date start,\n                                                                 @Param(\"end\") Date end);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    List<BillableTime> findByDateBetween(@Param(\"start\") Date start, @Param(\"end\") Date end);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/billtimes/BillableTimeWithProjectProjection.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = BillableTime.class, name = \"withProject\")\npublic interface BillableTimeWithProjectProjection {\n    Long getId();\n\n    Integer getVersion();\n\n    Project getProject();\n\n    Date getDate();\n\n    Integer getMinutes();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/ChangeStateService.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\n\n/**\n * @author Moritz Schulze\n */\npublic class ChangeStateService {\n\n    @Autowired\n    private InvoiceRepository invoiceRepository;\n\n    public Invoice changeState(Invoice invoice, Invoice.InvoiceState invoiceState) {\n        invoice.setInvoiceState(invoiceState);\n        return invoiceRepository.save(invoice);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/Invoice.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.hibernate.validator.constraints.NotEmpty;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.Min;\nimport javax.validation.constraints.NotNull;\nimport java.math.BigDecimal;\nimport java.util.Date;\n\n@Entity\n@Getter\n@Setter\n@Table(uniqueConstraints = @UniqueConstraint(columnNames = \"identifier\"))\npublic class Invoice {\n\n    public enum InvoiceState {\n        OUTSTANDING, PAID, OVERDUE\n    }\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @NotEmpty\n    private String identifier;\n\n    @NotNull\n    @Temporal(TemporalType.DATE)\n    private Date creationDate;\n\n    @Min(0)\n    private BigDecimal invoiceTotal;\n\n    @ManyToOne\n    @JoinColumn(name = \"debitor\")\n    private Company debitor;\n\n    @Temporal(TemporalType.DATE)\n    private Date dueDate;\n\n    @NotNull\n    @Enumerated(EnumType.STRING)\n    private InvoiceState invoiceState;\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceController.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(value = \"/invoices\")\npublic class InvoiceController {\n\n    @Autowired\n    private ChangeStateService changeStateService;\n\n    @Autowired\n    private InvoiceRepository invoiceRepository;\n\n    @RequestMapping(value = \"{id}/markPaid\", method = RequestMethod.POST)\n    @ResponseBody\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public String markAsPaid(@PathVariable(\"id\") Long invoiceId) {\n        Invoice invoice = invoiceRepository.findOne(invoiceId);\n        changeStateService.changeState(invoice, Invoice.InvoiceState.PAID);\n        return \"Ok.\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandler.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.time.LocalDate;\n\nimport static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;\n\n/**\n * @author Moritz Schulze\n */\n@RepositoryEventHandler(Invoice.class)\n@SuppressWarnings(\"unused\")\npublic class InvoiceEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void authorizeCreate(Invoice invoice) {\n        setDueDateFromTimeForPayment(invoice);\n        setInvoiceStateIfNecessary(invoice);\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void authorizeUpdate(Invoice invoice) {\n        setDueDateFromTimeForPayment(invoice);\n        setInvoiceStateIfNecessary(invoice);\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void authorizeDelete(Invoice invoice) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    public void linkSave(Invoice invoice, Object links) {\n        if (links instanceof Company) {\n            setDueDateFromTimeForPayment(invoice);\n            setInvoiceStateIfNecessary(invoice);\n        }\n    }\n\n    /**\n     * Sets the invoice state to OVERDUE if the due date is before today.\n     */\n    protected void setInvoiceStateIfNecessary(Invoice invoice) {\n        if (invoice.getDueDate() != null) {\n            LocalDate today = LocalDate.now();\n            if (invoice.getDueDate().before(fromLocalDate(today))) {\n                invoice.setInvoiceState(Invoice.InvoiceState.OVERDUE);\n            } else {\n                invoice.setInvoiceState(Invoice.InvoiceState.OUTSTANDING);\n            }\n        }\n    }\n\n    /**\n     * Set the due date automatically if it is not set and the debitor of the invoice has a timeForPayment.\n     */\n    protected void setDueDateFromTimeForPayment(Invoice invoice) {\n        if (invoice.getDueDate() == null && invoice.getDebitor() != null && invoice.getDebitor().getTimeForPayment() != null) {\n            LocalDate creationDate = LocalDateUtil.fromDate(invoice.getCreationDate());\n            LocalDate dueDate = creationDate.plusDays(invoice.getDebitor().getTimeForPayment());\n            invoice.setDueDate(LocalDateUtil.fromLocalDate(dueDate));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceOverdueService.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.time.LocalDate;\nimport java.util.List;\n\nimport static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;\n\n/**\n * Marks invoices as overdue if the due date is after today.\n * @author Moritz Schulze\n */\n@Slf4j\npublic class InvoiceOverdueService {\n\n    @Autowired\n    private InvoiceRepository invoiceRepository;\n\n    /**\n     * Mark all outstanding invoices with a due date after expiry date as overdue.\n     * @param expiryDate The date to use as a bound.\n     */\n    @Transactional\n    public void markOverdueInvoices(LocalDate expiryDate) {\n        List<Invoice> invoices = invoiceRepository.findByDueDateBeforeAndInvoiceState(fromLocalDate(expiryDate), Invoice.InvoiceState.OUTSTANDING);\n        for (Invoice invoice : invoices) {\n            log.info(\"Setting state to overdue on invoice {}\", invoice);\n            invoice.setInvoiceState(Invoice.InvoiceState.OVERDUE);\n            invoiceRepository.save(invoice);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceRepository.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.data.domain.Page;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport java.util.Date;\nimport java.util.List;\n\n/**\n * @author Moritz Schulze\n */\npublic interface InvoiceRepository extends JpaRepository<Invoice, Long> {\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    Invoice findOne(Long aLong);\n\n    @Override\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    Page<Invoice> findAll(Pageable pageable);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    Page<Invoice> findByInvoiceState(@Param(\"state\") Invoice.InvoiceState state, Pageable pageable);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    Page<Invoice> findByIdentifierLikeIgnoreCaseAndInvoiceState(@Param(\"identifier\") String identifier, @Param(\"state\") Invoice.InvoiceState state, Pageable pageable);\n\n    @RestResource(exported = false)\n    List<Invoice> findByDueDateBeforeAndInvoiceState(Date date, Invoice.InvoiceState invoiceState);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    List<Invoice> findByCreationDateBetween(@Param(\"start\") Date start, @Param(\"end\") Date end, @Param(\"sort\") Sort sort);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceScheduledJob.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.scheduling.annotation.Scheduled;\n\nimport java.time.LocalDate;\n\n/**\n * @author Moritz Schulze\n */\npublic class InvoiceScheduledJob {\n\n    @Autowired\n    private InvoiceOverdueService invoiceOverdueService;\n\n    @Scheduled(cron = \"0 0 1 * * *\")\n    public void markOverdueInvoices() {\n        LocalDate today = LocalDate.now();\n        invoiceOverdueService.markOverdueInvoices(today);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/invoice/InvoiceWithDebitorProjection.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.math.BigDecimal;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Projection(types = Invoice.class, name = \"withDebitor\")\npublic interface InvoiceWithDebitorProjection {\n    Long getId();\n\n    Integer getVersion();\n\n    String getIdentifier();\n\n    Date getCreationDate();\n\n    BigDecimal getInvoiceTotal();\n\n    Company getDebitor();\n\n    Date getDueDate();\n\n    Invoice.InvoiceState getInvoiceState();\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/CustomWorkTime.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.time.Duration;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\nimport static java.util.stream.Collectors.groupingBy;\nimport static java.util.stream.Collectors.reducing;\n\n/**\n * DTO that contains only the needed information for the method findEmployeeMappingByProjectAndDateBetween.\n */\n@Getter\n@Setter\npublic class CustomWorkTime implements Comparable<CustomWorkTime> {\n\n    private Date date;\n\n    private Long enteredMinutes;\n\n    private Double hours;\n\n    private Long billedTimeId;\n\n    private String comment;\n\n    /**\n     * Add up work times that belong to the same date.\n     *\n     * @param workTimes The worktimes to add\n     * @return A sorted list of worktimes.\n     */\n    public static List<CustomWorkTime> reduceAndSortWorktimes(List<CustomWorkTime> workTimes) {\n        CustomWorkTime identity = new CustomWorkTime();\n        identity.setEnteredMinutes(0L);\n        Map<Date, CustomWorkTime> mapped = workTimes.stream().collect(groupingBy(CustomWorkTime::getDate, reducing(identity, CustomWorkTime::addOtherWorkTime)));\n        return mapped.values().stream().sorted().collect(Collectors.toList());\n    }\n\n    private CustomWorkTime addOtherWorkTime(CustomWorkTime other) {\n        CustomWorkTime added = new CustomWorkTime();\n        added.setDate(other.getDate());\n        added.setEnteredMinutes(this.getEnteredMinutes() + other.getEnteredMinutes());\n        added.addComment(this.getComment());\n        added.addComment(other.getComment());\n        return added;\n    }\n\n    private void addComment(String comment) {\n        if (getComment() == null) {\n            setComment(comment);\n        } else if(comment != null) {\n            setComment(this.comment + \"\\n\" + comment);\n        }\n    }\n\n    public static CustomWorkTime valueOf(WorkTime workTime) {\n        CustomWorkTime customWorkTime = new CustomWorkTime();\n        customWorkTime.enteredMinutes = Duration.between(workTime.getStartTime().toLocalTime(), workTime.getEndTime().toLocalTime()).toMinutes();\n        customWorkTime.date = workTime.getDate();\n        customWorkTime.comment = workTime.getComment();\n        return customWorkTime;\n    }\n\n    @Override\n    public int compareTo(CustomWorkTime o) {\n        return this.getDate().compareTo(o.getDate());\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n\n        CustomWorkTime that = (CustomWorkTime) o;\n\n        return !(date != null ? !date.equals(that.date) : that.date != null);\n\n    }\n\n    @Override\n    public int hashCode() {\n        return date != null ? date.hashCode() : 0;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/Projections.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.data.rest.core.config.Projection;\n\nimport java.sql.Time;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\npublic class Projections {\n    @Projection(types = WorkTime.class, name = \"withEmployee\")\n    public interface WorkTimeWithEmployeeProjection {\n        Long getId();\n\n        Integer getVersion();\n\n        Employee getEmployee();\n\n        Date getDate();\n\n        Time getStartTime();\n\n        Time getEndTime();\n\n        String getComment();\n    }\n\n    @Projection(types = WorkTime.class, name = \"withProject\")\n    public interface WorkTimeWithProjectProjection {\n        Long getId();\n\n        Integer getVersion();\n\n        Project getProject();\n\n        Date getDate();\n\n        Time getStartTime();\n\n        Time getEndTime();\n\n        String getComment();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTime.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotNull;\nimport java.sql.Time;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\n@Entity\n@Getter\n@Setter\n@EndAfterBegin(begin = \"startTime\", end = \"endTime\")\npublic class WorkTime {\n\n    @Id\n    @GeneratedValue(strategy = GenerationType.AUTO)\n    private Long id;\n\n    @Version\n    private Integer version;\n\n    @ManyToOne\n    @NotNull\n    @JoinColumn(name = \"employee\")\n    private Employee employee;\n\n    @ManyToOne\n    @NotNull\n    @JoinColumn(name = \"project\")\n    private Project project;\n\n    @NotNull\n    @Temporal(TemporalType.DATE)\n    private Date date;\n\n    private Time startTime;\n\n    private Time endTime;\n\n    private String comment;\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeController.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.project.billtimes.BillableTime;\nimport de.techdev.trackr.domain.project.billtimes.BillableTimeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport org.springframework.core.convert.ConversionService;\nimport org.springframework.hateoas.EntityLinks;\nimport org.springframework.hateoas.Link;\nimport org.springframework.http.MediaType;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\n\nimport static java.util.stream.Collectors.*;\n\n/**\n * @author Moritz Schulze\n */\n@Controller\n@RequestMapping(\"/workTimes\")\npublic class WorkTimeController {\n\n    @Autowired\n    @Qualifier(\"defaultConversionService\")\n    private ConversionService conversionService;\n\n    @Autowired\n    private WorkTimeRepository workTimeRepository;\n\n    @Autowired\n    private BillableTimeRepository billableTimeRepository;\n\n    @Autowired\n    protected EntityLinks repositoryEntityLinks;\n\n    /**\n     * Finds all workTimes for a project in a given interval and converts them to a mapping of employee id to worktimes.\n     *\n     * @param projectId The id of the project\n     * @param start     The start of the interval\n     * @param end       The end of the interval\n     * @return The mapping of employee id to a DTO object that contains the employee along the work times.\n     */\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    @RequestMapping(value = \"/findEmployeeMappingByProjectAndDateBetween\", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\n    @ResponseBody\n    public Map<Long, WorkTimeEmployee> findEmployeeMappingByProjectAndDateBetween(\n            @RequestParam(\"project\") String projectId,\n            @RequestParam(\"start\") Date start,\n            @RequestParam(\"end\") Date end) {\n        //TODO: Make spring do the conversion automatically\n        Project project = conversionService.convert(Long.valueOf(projectId), Project.class);\n        List<WorkTime> workTimes = workTimeRepository.findByProjectAndDateBetweenOrderByDateAscStartTimeAsc(project, start, end);\n        return convertStreamOfWorkTimesToMap(workTimes, getBilledMinutesMapping(start, end, project));\n    }\n\n    /**\n     * Maps employees via id to the already billed times in a given interval.\n     *\n     * @param start   The start of the interval\n     * @param end     The end of the interval\n     * @param project The project\n     * @return A map of employee id to a map of date to billable times.\n     */\n    protected Map<Long, Map<Date, BillableTime>> getBilledMinutesMapping(Date start, Date end, Project project) {\n        List<BillableTime> billableTimes = billableTimeRepository.findByProjectAndDateBetweenOrderByDateAsc(project, start, end);\n        return billableTimes.stream().collect(\n                groupingBy(bt -> bt.getEmployee().getId(),\n                        mapping(billableTime -> billableTime,\n                                toMap(BillableTime::getDate, Function.<BillableTime>identity()))));\n    }\n\n    /**\n     * Takes a list of workTimes, groups them by employee while transforming the WorkTime objects to CustomWorkTime DTOs and afterwards maps it\n     * to a map of long (employee id) to the WorkTimeEmployee DTO.\n     *\n     * @param workTimes            The list of worktimes to transform\n     * @param billedMinutesMapping Mapping of already billed minutes\n     * @return The mapping of Long to WorkTimeEmployee\n     */\n    protected Map<Long, WorkTimeEmployee> convertStreamOfWorkTimesToMap(List<WorkTime> workTimes, Map<Long, Map<Date, BillableTime>> billedMinutesMapping) {\n        return workTimes.stream().collect(\n                groupingBy(\n                        WorkTime::getEmployee,\n                        mapping(CustomWorkTime::valueOf, toList())\n                )).entrySet().stream().collect(\n                HashMap<Long, WorkTimeEmployee>::new,\n                (resultMap, entry) -> {\n                    Link link = repositoryEntityLinks.linkToSingleResource(Employee.class, entry.getKey().getId());\n                    WorkTimeEmployee workTimeEmployee = WorkTimeEmployee.valueOf(entry.getKey(), entry.getValue());\n                    workTimeEmployee.addBilledMinutes(billedMinutesMapping.get(entry.getKey().getId()));\n                    workTimeEmployee.add(link.withSelfRel());\n                    resultMap.put(entry.getKey().getId(), workTimeEmployee);\n                },\n                HashMap<Long, WorkTimeEmployee>::putAll);\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEmployee.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.billtimes.BillableTime;\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework.hateoas.ResourceSupport;\n\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * DTO that contains only the needed information for the method findEmployeeMappingByProjectAndDateBetween.\n * <p>\n * It extends {@link org.springframework.hateoas.ResourceSupport} so a link to the employee entity can be added.\n */\n@Getter\n@Setter\n@EqualsAndHashCode(callSuper = false)\npublic class WorkTimeEmployee extends ResourceSupport {\n    private String name;\n    private List<CustomWorkTime> workTimes;\n\n    /**\n     * Create a WorkTimeEmployee out of an Employee and a list of workTimes. It is the responsibility of the caller to\n     * assure that the workTimes belong to the employee.\n     * <p>\n     * This method will aggregate the workTimes by date and sum up the worked hours.\n     *\n     * @param employee  The employee to use\n     * @param workTimes The list of workTimes to use.\n     * @return A workTime employee\n     */\n    public static WorkTimeEmployee valueOf(Employee employee, List<CustomWorkTime> workTimes) {\n        WorkTimeEmployee workTimeEmployee = new WorkTimeEmployee();\n        workTimeEmployee.name = employee.fullName();\n        workTimeEmployee.workTimes = CustomWorkTime.reduceAndSortWorktimes(workTimes);\n        return workTimeEmployee;\n    }\n\n    public void addBilledMinutes(Map<Date, BillableTime> dateBillableTimeMapping) {\n        workTimes.forEach(ctw -> {\n            if(dateBillableTimeMapping != null && dateBillableTimeMapping.get(ctw.getDate()) != null) {\n                ctw.setBilledTimeId(dateBillableTimeMapping.get(ctw.getDate()).getId());\n                ctw.setHours(dateBillableTimeMapping.get(ctw.getDate()).getMinutes().doubleValue() / 60);\n            }\n        });\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeEventHandler.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.springframework.data.rest.core.annotation.*;\nimport org.springframework.security.access.prepost.PreAuthorize;\nimport org.springframework.web.HttpRequestMethodNotSupportedException;\n\n@RepositoryEventHandler(WorkTime.class)\n@SuppressWarnings(\"unused\")\npublic class WorkTimeEventHandler {\n\n    @HandleBeforeCreate\n    @PreAuthorize(\"#workTime.employee.email == principal?.username\")\n    public void checkCreateAuthority(WorkTime workTime) {\n    }\n\n    @HandleBeforeSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN') or #workTime.employee.email == principal?.username\")\n    public void checkUpdateAuthority(WorkTime workTime) {\n    }\n\n    @HandleBeforeDelete\n    @PreAuthorize(\"hasRole('ROLE_ADMIN') or #workTime.employee.email == principal?.username\")\n    public void checkDeleteAuthority(WorkTime workTime) {\n    }\n\n    @HandleBeforeLinkSave\n    @PreAuthorize(\"hasRole('ROLE_ADMIN') or #workTime.employee.email == principal?.username\")\n    public void checkUpdateLinkAuthority(WorkTime workTime, Object link) throws HttpRequestMethodNotSupportedException {\n        if(Employee.class.isAssignableFrom(link.getClass())) {\n            throw new HttpRequestMethodNotSupportedException(\"POST\", new String[0]);\n        }\n    }\n\n    @HandleBeforeLinkDelete\n    @PreAuthorize(\"denyAll()\")\n    public void checkDeleteLinkAuthority(WorkTime workTime, Object linkedEntity) {\n        //deny all, cannot be called\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/project/worktimes/WorkTimeRepository.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.project.Project;\nimport org.springframework.data.jpa.repository.Temporal;\nimport org.springframework.data.repository.CrudRepository;\nimport org.springframework.data.repository.query.Param;\nimport org.springframework.data.rest.core.annotation.RestResource;\nimport org.springframework.security.access.prepost.PostAuthorize;\nimport org.springframework.security.access.prepost.PreAuthorize;\n\nimport javax.persistence.TemporalType;\nimport java.util.Date;\nimport java.util.List;\n\npublic interface WorkTimeRepository extends CrudRepository<WorkTime, Long> {\n\n    @Override\n    @RestResource(exported = false)\n    List<WorkTime> findAll();\n\n    @Override\n    @RestResource(exported = false)\n    List<WorkTime> findAll(Iterable<Long> longs);\n\n    @Override\n    @PostAuthorize(\"hasRole('ROLE_SUPERVISOR') or returnObject.employee.email == principal?.username\")\n    WorkTime findOne(Long aLong);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #employee.email == principal?.username\")\n    List<WorkTime> findByEmployeeAndDateOrderByStartTimeAsc(@Param(\"employee\") Employee employee, @Param(\"date\") @Temporal(TemporalType.DATE) Date date);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR') or #employee.email == principal?.username\")\n    List<WorkTime> findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc(@Param(\"employee\") Employee employee,\n                                                                          @Param(\"start\") @Temporal(TemporalType.DATE) Date start,\n                                                                          @Param(\"end\") @Temporal(TemporalType.DATE) Date end);\n\n    @PreAuthorize(\"hasRole('ROLE_SUPERVISOR')\")\n    List<WorkTime> findByProjectAndDateBetweenOrderByDateAscStartTimeAsc(@Param(\"project\") Project project,\n                                                                         @Param(\"start\") @Temporal(TemporalType.DATE) Date start,\n                                                                         @Param(\"end\") @Temporal(TemporalType.DATE) Date end);\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN')\")\n    List<WorkTime> findByDateBetween(@Param(\"start\") Date start, @Param(\"end\") Date end);\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/scheduling/LastWorkdayDayOfMonthTrigger.java",
    "content": "package de.techdev.trackr.domain.scheduling;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.employee.vacation.HolidayRepository;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport lombok.Setter;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.scheduling.Trigger;\nimport org.springframework.scheduling.TriggerContext;\n\nimport java.time.DayOfWeek;\nimport java.time.LocalDate;\nimport java.time.temporal.TemporalAdjusters;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport static de.techdev.trackr.util.LocalDateUtil.fromDate;\nimport static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;\n\n/**\n * A trigger that is executed on the last workday in the month.\n *\n * @author Moritz Schulze\n */\n@Setter\n@Slf4j\npublic class LastWorkdayDayOfMonthTrigger implements Trigger {\n\n    @Autowired\n    private HolidayRepository holidayRepository;\n\n    private FederalState federalState;\n\n    /**\n     * Get a list of all holidays for a state and month as {@link java.time.LocalDate}.\n     *\n     * @param state The federal state\n     * @param month The month\n     * @return The list of public holidays in the state in the month.\n     */\n    protected List<LocalDate> getHolidaysForMonth(FederalState state, LocalDate month) {\n        LocalDate firstDayOfMonth = month.with(TemporalAdjusters.firstDayOfMonth());\n        LocalDate lastDayOfMonth = month.with(TemporalAdjusters.lastDayOfMonth());\n        return holidayRepository\n                .findByFederalStateAndDayBetween(state, fromLocalDate(firstDayOfMonth), fromLocalDate(lastDayOfMonth))\n                .stream().map(holiday -> fromDate(holiday.getDay()))\n                .collect(Collectors.toList());\n    }\n\n    /**\n     * Get the last day in month that is not a saturday or sunday or public holiday.\n     *\n     * @param month               The month\n     * @param holidaysInThisMonth A list of holidays for the given month\n     * @return New date with the last day that is not saturday or sunday or public holiday in the month.\n     */\n    protected LocalDate lastWeekdayInMonth(LocalDate month, List<LocalDate> holidaysInThisMonth) {\n        LocalDate returnDate = month.with(TemporalAdjusters.lastDayOfMonth());\n        while (!isWorkday(returnDate, holidaysInThisMonth)) {\n            returnDate = returnDate.minusDays(1);\n        }\n        return returnDate;\n    }\n\n    /**\n     * Decides whether a date is a work day or not (i.e. not a saturday, sunday or a public holiday).\n     *\n     * @param date     The date to check\n     * @param holidays A list of holidays to use\n     * @return true if the day is not a sunday, saturday or in the list of holidays.\n     */\n    protected boolean isWorkday(LocalDate date, List<LocalDate> holidays) {\n        return date.getDayOfWeek() != DayOfWeek.SATURDAY && date.getDayOfWeek() != DayOfWeek.SUNDAY\n                && !holidays.contains(date);\n    }\n\n    @Override\n    public Date nextExecutionTime(TriggerContext triggerContext) {\n        return fromLocalDate(nextExecutionTimeInternal(triggerContext));\n    }\n\n    protected LocalDate nextExecutionTimeInternal(TriggerContext triggerContext) {\n        LocalDate now = LocalDate.now();\n        if (triggerContext.lastScheduledExecutionTime() != null &&\n                LocalDateUtil.fromDate(triggerContext.lastScheduledExecutionTime()).getMonth() == now.getMonth()) {\n            now = now.plusMonths(1);\n        }\n        LocalDate nextExecutionTime = lastWeekdayInMonth(now, getHolidaysForMonth(federalState, now));\n        log.debug(\"Trigger for state {} sets next execution date to {}\", federalState, nextExecutionTime);\n        return nextExecutionTime;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/scheduling/ScheduledJobsConfiguration.java",
    "content": "package de.techdev.trackr.domain.scheduling;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.employee.EmployeeScheduledJob;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequestScheduledJobs;\nimport de.techdev.trackr.domain.project.invoice.InvoiceScheduledJob;\nimport org.springframework.beans.factory.config.BeanDefinition;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.scheduling.annotation.EnableScheduling;\nimport org.springframework.scheduling.annotation.SchedulingConfigurer;\nimport org.springframework.scheduling.config.ScheduledTaskRegistrar;\nimport org.springframework.security.authentication.UsernamePasswordAuthenticationToken;\nimport org.springframework.security.concurrent.DelegatingSecurityContextScheduledExecutorService;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.context.SecurityContext;\nimport org.springframework.security.core.context.SecurityContextHolder;\n\nimport java.util.List;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport static java.util.Arrays.asList;\n\n/**\n * @author Moritz Schulze\n */\n@Configuration\n@EnableScheduling\npublic class ScheduledJobsConfiguration implements SchedulingConfigurer {\n\n    @Bean\n    public VacationRequestScheduledJobs vacationScheduledJobs() {\n        return new VacationRequestScheduledJobs();\n    }\n\n    @Bean\n    public EmployeeScheduledJob employeeScheduledJob() {\n        return new EmployeeScheduledJob();\n    }\n\n    @Bean\n    @Scope(BeanDefinition.SCOPE_PROTOTYPE)\n    public LastWorkdayDayOfMonthTrigger lastWorkdayDayOfMonthTrigger() {\n        return new LastWorkdayDayOfMonthTrigger();\n    }\n\n    @Bean\n    public InvoiceScheduledJob invoiceScheduledJob() {\n        return new InvoiceScheduledJob();\n    }\n\n    @Override\n    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {\n        taskRegistrar.setScheduler(taskExecutor());\n        for (FederalState federalState : FederalState.values()) {\n            LastWorkdayDayOfMonthTrigger trigger = lastWorkdayDayOfMonthTrigger();\n            trigger.setFederalState(federalState);\n            taskRegistrar.addTriggerTask(employeeScheduledJob().sendWorkTimeReminderTask(federalState), trigger);\n        }\n    }\n\n    /**\n     * @return An executor that has admin rights.\n     */\n    @Bean(destroyMethod = \"shutdownNow\")\n    public Executor taskExecutor() {\n        ScheduledExecutorService delegateExecutor = Executors.newSingleThreadScheduledExecutor();\n        SecurityContext schedulerContext = createSchedulerSecurityContext();\n        return new DelegatingSecurityContextScheduledExecutorService(delegateExecutor, schedulerContext);\n    }\n\n    /**\n     * @return A security context with an admin authentication token.\n     */\n    private SecurityContext createSchedulerSecurityContext() {\n        SecurityContext context = SecurityContextHolder.createEmptyContext();\n        List<GrantedAuthority> grantedAuthorities = asList((GrantedAuthority) () -> \"ROLE_ADMIN\");\n        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(\"admin@techdev.de\", \"\", grantedAuthorities);\n        context.setAuthentication(authenticationToken);\n        return context;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/translations/TranslationController.java",
    "content": "package de.techdev.trackr.domain.translations;\n\nimport de.techdev.trackr.domain.employee.Settings;\nimport de.techdev.trackr.domain.employee.SettingsRepository;\nimport lombok.extern.slf4j.Slf4j;\nimport org.apache.commons.io.IOUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.ClassPathResource;\nimport org.springframework.http.MediaType;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.servlet.LocaleResolver;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.security.Principal;\nimport java.util.Locale;\n\n@Controller\n@RequestMapping(\"/translations\")\n@Slf4j\npublic class TranslationController {\n\n    @Autowired\n    private LocaleResolver localeResolver;\n\n    @Autowired\n    private SettingsRepository settingsRepository;\n\n    @RequestMapping(method = RequestMethod.GET)\n    public void getTranslations(Locale locale, HttpServletResponse response) {\n        ClassPathResource translationFile = new ClassPathResource(\"/i18n/trackr-\" + locale.toLanguageTag() + \".json\");\n        response.setHeader(\"Content-Type\", MediaType.APPLICATION_JSON_VALUE);\n        response.setCharacterEncoding(\"UTF-8\");\n        try {\n            IOUtils.copy(translationFile.getInputStream(), response.getWriter(), \"UTF-8\");\n            response.setStatus(200);\n            response.getWriter().close();\n        } catch (IOException e) {\n            throw new IllegalStateException(\"Could not open translation file\", e);\n        }\n    }\n\n    @RequestMapping(method = RequestMethod.PUT, produces = MediaType.TEXT_PLAIN_VALUE)\n    @ResponseBody\n    public String setLocale(@RequestParam(\"locale\") Locale locale, HttpServletRequest request, HttpServletResponse response, Principal principal) {\n        localeResolver.setLocale(request, response, locale);\n        Settings localeSettings = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, principal.getName());\n        if (localeSettings == null) {\n            log.error(\"Employee {} without locale settings.\", principal.getName());\n            return \"Ok.\";\n        }\n        localeSettings.setValue(locale.getLanguage());\n        settingsRepository.save(localeSettings);\n        return \"Ok.\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/validation/EndAfterBeginValidator.java",
    "content": "package de.techdev.trackr.domain.validation;\n\nimport de.techdev.trackr.domain.validation.constraints.EndAfterBegin;\nimport org.springframework.beans.DirectFieldAccessor;\n\nimport javax.validation.ConstraintValidator;\nimport javax.validation.ConstraintValidatorContext;\nimport java.util.Date;\n\n/**\n * @author Moritz Schulze\n */\npublic class EndAfterBeginValidator implements ConstraintValidator<EndAfterBegin, Object> {\n\n    private String beginFieldName;\n    private String endFieldName;\n    private String messageTemplate;\n\n    @Override\n    public void initialize(EndAfterBegin constraintAnnotation) {\n        beginFieldName = constraintAnnotation.begin();\n        endFieldName = constraintAnnotation.end();\n        messageTemplate = constraintAnnotation.message();\n    }\n\n    @Override\n    public boolean isValid(Object value, ConstraintValidatorContext context) {\n        DirectFieldAccessor dfa = new DirectFieldAccessor(value);\n        Class<?> beginFieldType = dfa.getPropertyType(beginFieldName);\n        Class<?> endFieldType = dfa.getPropertyType(endFieldName);\n\n        if(! (Date.class.isAssignableFrom(beginFieldType) || Date.class.isAssignableFrom(endFieldType)) ) {\n            throw new IllegalArgumentException(\"Fields are not date objects.\");\n        }\n        Date beginField = (Date) dfa.getPropertyValue(beginFieldName);\n        Date endField = (Date) dfa.getPropertyValue(endFieldName);\n\n        boolean isValid = beginField == null || endField == null || !beginField.after(endField);\n        if (!isValid) {\n            context.disableDefaultConstraintViolation();\n            context.\n                    buildConstraintViolationWithTemplate(messageTemplate)\n                    .addNode(endFieldName).addConstraintViolation();\n        }\n        return isValid;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/validation/ProjectBelongsToCompanyValidator.java",
    "content": "package de.techdev.trackr.domain.validation;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.validation.constraints.ProjectBelongsToCompany;\nimport org.springframework.beans.DirectFieldAccessor;\n\nimport javax.validation.ConstraintValidator;\nimport javax.validation.ConstraintValidatorContext;\n\n/**\n * @author Moritz Schulze\n */\npublic class ProjectBelongsToCompanyValidator implements ConstraintValidator<ProjectBelongsToCompany, Object> {\n\n    private String projectFieldName;\n    private String companyFieldName;\n    private String messageTemplateName;\n\n    @Override\n    public void initialize(ProjectBelongsToCompany constraintAnnotation) {\n        companyFieldName = constraintAnnotation.companyField();\n        projectFieldName = constraintAnnotation.projectField();\n        messageTemplateName = constraintAnnotation.message();\n    }\n\n    @Override\n    public boolean isValid(Object value, ConstraintValidatorContext context) {\n        boolean isValid = true;\n        DirectFieldAccessor dfa = new DirectFieldAccessor(value);\n        Object project = dfa.getPropertyValue(projectFieldName);\n        if (project != null) {\n            Company company = (Company) dfa.getPropertyValue(companyFieldName);\n            isValid = ((Project) project).getCompany().getId().equals(company.getId());\n        }\n        if (!isValid) {\n            context.disableDefaultConstraintViolation();\n            context.buildConstraintViolationWithTemplate(messageTemplateName)\n                    .addNode(projectFieldName).addConstraintViolation();\n        }\n        return isValid;\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/validation/constraints/EndAfterBegin.java",
    "content": "package de.techdev.trackr.domain.validation.constraints;\n\nimport de.techdev.trackr.domain.validation.EndAfterBeginValidator;\n\nimport javax.validation.Constraint;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Checks that the begin field is not after the end date, but they may be the same.\n *\n * @author Moritz Schulze\n */\n@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Constraint(validatedBy = EndAfterBeginValidator.class)\npublic @interface EndAfterBegin {\n\n    Class[] groups() default {};\n\n    Class[] payload() default {};\n\n    String message() default \"{validation.date.endAfterBegin}\";\n\n    String begin();\n\n    String end();\n\n    @interface List {\n        EndAfterBegin[] value();\n    }\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/domain/validation/constraints/ProjectBelongsToCompany.java",
    "content": "package de.techdev.trackr.domain.validation.constraints;\n\nimport de.techdev.trackr.domain.validation.ProjectBelongsToCompanyValidator;\n\nimport javax.validation.Constraint;\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * Validation that checks if a project field, if it is not null, belongs to a company field.\n *\n * @author Moritz Schulze\n */\n@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})\n@Retention(RetentionPolicy.RUNTIME)\n@Constraint(validatedBy = ProjectBelongsToCompanyValidator.class)\npublic @interface ProjectBelongsToCompany {\n\n    Class[] groups() default {};\n\n    Class[] payload() default {};\n\n    String message() default \"{validation.company.projectBelongsTo}\";\n\n    String companyField() default \"company\";\n\n    String projectField() default \"project\";\n\n}\n"
  },
  {
    "path": "src/main/java/de/techdev/trackr/util/LocalDateUtil.java",
    "content": "package de.techdev.trackr.util;\n\nimport java.time.Instant;\nimport java.time.LocalDate;\nimport java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.util.Date;\n\n/**\n * Convert {@link java.util.Date} from and to {@link java.time.LocalDate}\n * @author Moritz Schulze\n */\npublic final class LocalDateUtil {\n\n    private LocalDateUtil() {\n    }\n\n    public static Date fromLocalDate(LocalDate date) {\n        Instant instant = date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();\n        return Date.from(instant);\n    }\n\n    public static LocalDate fromDate(Date date) {\n        Instant instant = Instant.ofEpochMilli(date.getTime());\n        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).toLocalDate();\n    }\n}\n"
  },
  {
    "path": "src/main/resources/META-INF/mail-integration.xml",
    "content": "<beans:beans xmlns=\"http://www.springframework.org/schema/integration\"\n             xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n             xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd\n                http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd\n                http://www.springframework.org/schema/integration/mail http://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd\"\n             xmlns:beans=\"http://www.springframework.org/schema/beans\"\n             xmlns:int-mail=\"http://www.springframework.org/schema/integration/mail\">\n\n    <channel id=\"mailSendChannel\" datatype=\"org.springframework.mail.MailMessage\">\n        <queue capacity=\"1000\"/>\n    </channel>\n\n    <int-mail:outbound-channel-adapter id=\"test\" channel=\"mailSendChannel\" mail-sender=\"mailSender\">\n        <poller fixed-delay=\"60000\"/>\n    </int-mail:outbound-channel-adapter>\n\n    <!-- Disabled for performance reasons -->\n    <!--<beans:beans profile=\"gmail\">-->\n        <!--<channel id=\"receiveChannel\" datatype=\"javax.mail.Message\"/>-->\n\n        <!--<int-mail:imap-idle-channel-adapter id=\"customAdapter\"-->\n                                            <!--store-uri=\"imaps://no-reply%40techdev.de:${spring.mail.password}@imap.gmail.com:993/inbox\"-->\n                                            <!--channel=\"receiveChannel\"-->\n                                            <!--session=\"mailSession\"-->\n                                            <!--auto-startup=\"true\"-->\n                                            <!--should-delete-messages=\"false\"-->\n                                            <!--should-mark-messages-as-read=\"true\"/>-->\n\n        <!--<service-activator input-channel=\"receiveChannel\" ref=\"mailApproveService\" method=\"approveOrRejectFromMail\"/>-->\n        <!--mail-filter-expression=\"subject matches '(?i).*TRACKR.*'\"-->\n    <!--</beans:beans>-->\n</beans:beans>"
  },
  {
    "path": "src/main/resources/banner.txt",
    "content": "                                                                                                   \n                                                                                                   \n                                                                                                   \n                                                                                                   \n                                   ...........                                                     \n                            ............................                                           \n                         ..........................     .....                                      \n                       ................................     ....                                   \n                      .,.....................................  .....                               \n                     ..................................................                            \n                                    ......................................                         \n                                         ...................................                       \n                                              ................................                     \n                                                  ..............................                   \n                   ...,,,,,,,,....                  ..............................                 \n              ,**////////////////////*,.              ....................,,,......                \n          .*//////////////////////////////,..     ....,,,(###%%%%%%%####((//*,,,.....              \n        .,///////////////////////////////////,,,,,,*******(#%%%%%%%%%%%%%%%%%##(/*,...             \n       .///////////////////////////////((##%%%%#***********/%%%%%%%%%%%%%%%%%%%%%%%#(,..           \n      .*///////////////////////////((#%%%%%%%%%%%#/*********#%%%%%%%%%%%%%%%%%%%%%%%%%#/           \n      .*///////////////////////((#%%%%%%%%%%%%%%%%#*********/#%%%%%%%%%%%%%%%%%%%%%%%%%%(,         \n       */////////////////////((#%%%%%%%%%%%%%%%%%%%/********/#%%%%%%%%%%%%%%%%%%%%%%%%%%#*         \n       .///////////////////(#%%%%%%%%%%%%%%%%%%%%%%(********/(%%%%%%%%%%%%%%%%%%%%%%%%%%%(,        \n        *////////////////#%%%%%%%%%%%%%%%%%%%%%%%%%/********/#%%%%%%%%%%%%%%%%%%%%%%%%%%%#*        \n        .*/////////////(#%%%%%%%%%%%%%%%%%%%%%%%%%%*********/#%%%%%%%%%%%%%%%%%%%%%%%%%%%#,        \n         .*//////////(#%%%%%%%%%%%%%%%%%%%%%%%%%%#(*********#%%%%%%%%%%%%%%%%%%%%%%%%%%%%/.        \n           *///////(#%%%%%%%%%%%%%%%%%%%%%%%%%%%#/*********/%%%%%%%%%%%%%%%%%%%%%%%%%%%%(,         \n           .*//////#%%%%%%%%%%%%%%%%%%%%%%%%%%%%/**********(%%%%%%%%%%%%%%%%%%%%%%%%%%%%,          \n             .////(%%%%%%%%%%%%%%%%%%%%%%%%%%#(/*********/#%%%%%%%%%%%%%%%%%%%%%%%%%%%#/           \n               ,*(#%%%%%%%%%%%%%%%%%%%%%%%%%#***********/%%%%%%%%%%%%%%%%%%%%%%%%%%%%/.            \n                 *(%%%%%%%%%%%%%%%%%%%%%%#/***********/#%%%%%%%%%%%%%%%%%%%%%%%%%%%(*              \n                   /#%%%%%%%%%%%%%%%%%%#(/************#%%%%%%%%%%%%%%%%%%%%%%%%%%%*.               \n                      ,/(#%%%%%%%%##(/*************/#%%%%%%%%%%%%%%%%%%%%%%%%%%#,                  \n                               ,*****************/(%%%%%%%%%%%%%%%%%%%%%%%%%#,                     \n                                .,**************##%%%%%%%%%%%%%%%%%%%%%%%#*,                       \n                                   .,********##%%%%%%%%%%%%%%%%%%%%%%#/.                           \n                                       ,*/#%%%%%%%%%%%%%%%%%%%%##*,.                               \n                                         .*/(##%%%%%%%%%%##(/*..                                   \n                                                                                                   \n                                                                                                   \n                                                                                                   \n                                     ........,,,,,,,,,,,,,,,,,.........                            \n                                       .............................                               \n                                                                              \n"
  },
  {
    "path": "src/main/resources/data.sql",
    "content": "CREATE TABLE IF NOT EXISTS uuid_mapping (id int, uuid varchar);\n\n/* EMPLOYEE ADDRESSES */\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (19, 0, 'Berliner Strasse', '94', '10117', 'Berlin', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (20, 0, 'Frankfurter Strasse', '1a', '10318', 'Berlin', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (21, 0, 'Architektenallee', '666', '76123', 'Karlsruhe', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (22, 0, 'Holzweg', '5', '64291', 'Darmstadt', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (23, 0, 'Ahornallee', '187', '10589', 'Berlin', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (24, 0, 'Markgrafenstrasse', '79', '15230', 'Berlin', 'Deutschland');\nINSERT INTO address (id, version, street, housenumber, zipCode, city, country) VALUES (25, 0, 'Kurfuerstendamm', '461', '10234', 'Berlin', 'Deutschland');\n\n/* EMPLOYEES */\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, address_id, deleted) VALUES (1, 0, 'moritz.schulze@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 50000, 'BERLIN', '2014-02-01', 30, 19, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, address_id, deleted) VALUES (2, 0, 'markus.kappel@techdev.de', 'Adam', 'Smith', 'Software Consultant', 85, 55000, 'BERLIN', '2014-07-01', 20, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, address_id, deleted) VALUES (3, 0, 'alexander.hanschke@techdev.de', 'William', 'Hanson', 'CEO', 85, 60000, 'BADEN_WUERTTEMBERG', '2013-09-01', 21, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, address_id, deleted) VALUES (4, 0, 'adrian.krion@techdev.de','Bill', 'Rust', 'Processes Consultant', 87, 58000, 'HESSEN', '2014-01-01', 22, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, deleted) VALUES (5, 0, 'angelika.gutjahr@techdev.de', 'Jane', 'Dafoe', 'HR', 0, 500000, 'BADEN_WUERTTEMBERG', '2013-10-01', false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, address_id, deleted) VALUES (6, 0, 'nikolaj.weise@techdev.de', 'Horace', 'Nottingham', 'External Consultant', 90, 0, 'BERLIN', 23, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, address_id, deleted) VALUES (7, 0, 'jochen.toepfer@techdev.de', 'Vladimir', 'Wichowsko', 'Software Engineer', 80, 49000, 'BERLIN', '2013-11-01', 24, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, address_id, deleted) VALUES (8, 0, 'mehmed.halilovic@techdev.de', 'John', 'Hooper', 'Software Architect', 90, 65000, 'BERLIN', '2014-09-01', 25, false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, deleted) VALUES (9, 0, 'noop3@techdev.de', 'Todd', 'Floyd', 'HR', 0, 45000, 'BADEN_WUERTTEMBERG', '2014-03-16', false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, leaveDate, deleted) VALUES (10, 0, 'noop4@techdev.de', 'Joanne', 'Doughty', 'Practicant', 0, 25000, 'SCHLESWIG_HOLSTEIN', '2013-11-01', '2013-12-15', false);\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, deleted) VALUES (11, 0, 'supervisor@techdev.de', 'Sean', 'Robinson', 'Software Engineer', 75, 51000, 'MECKLENBURG_VORPOMMERN', '2014-05-01', false);\n\nINSERT INTO settings (id, type, value, employee_id) VALUES (0, 'LOCALE', 'en', 1);\nINSERT INTO settings (id, type, value, employee_id) VALUES (1, 'LOCALE', 'de', 2);\nINSERT INTO settings (id, type, value, employee_id) VALUES (2, 'LOCALE', 'de', 3);\nINSERT INTO settings (id, type, value, employee_id) VALUES (3, 'LOCALE', 'en', 4);\nINSERT INTO settings (id, type, value, employee_id) VALUES (4, 'LOCALE', 'en', 5);\nINSERT INTO settings (id, type, value, employee_id) VALUES (5, 'LOCALE', 'en', 6);\nINSERT INTO settings (id, type, value, employee_id) VALUES (6, 'LOCALE', 'en', 7);\nINSERT INTO settings (id, type, value, employee_id) VALUES (7, 'LOCALE', 'en', 8);\nINSERT INTO settings (id, type, value, employee_id) VALUES (8, 'LOCALE', 'en', 9);\nINSERT INTO settings (id, type, value, employee_id) VALUES (9, 'LOCALE', 'en', 10);\nINSERT INTO settings (id, type, value, employee_id) VALUES (10, 'LOCALE', 'en', 11);\n\n/* (COMPANY) ADDRESSES */\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (15, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (16, 0, 'Berliner Straße', '125', '60139', 'Frankfurt', 'Deutschland');\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (17, 0, 'Holzweg', '2', '10521', 'Berlin', 'Deutschland');\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (18, 0, 'Temple Road', '67', '40931', 'Düsseldorf', 'Deutschland');\n\n/* COMPANIES */\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (19, 0, 1000, 'webshop Ltd.', 15, 30);\nINSERT INTO company (id, version, companyId, name, address_id) VALUES (20, 0, 1001, 'finance Meier & partners', 16);\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (21, 0, 1002, 'Origins', 17, 14);\nINSERT INTO company (id, version, companyId, name, address_id) VALUES (22, 0, 1003, 'scalar deployment GmbH', 18);\n\n/* CONTACT PERSONS */\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, company, roles) VALUES (23, 0, 'Robert', 'Lake', 'r.lake@webshop.de', 'Mr', '0178/11234566', 19, 'Sales Manager');\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, company, roles) VALUES (24, 0, 'Lori', 'Carter', 'l.carter@webshop.de', 'Mrs', '0178/68203493', 19, 'Project Managerin, CIO');\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, company) VALUES (25, 0, 'Loyd', 'Boyden', 'loyd.boyden@fi-meyer.com', 'Mr', '0152 12039411', 20);\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, company) VALUES (26, 0, 'Jimmy', 'Green', 'jim.green@origins.de', 'Mr', '0176/60012331', 21);\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, company) VALUES (27, 0, 'Nichole', 'Morgan', 'n.morgan@scalard.net', 'Mrs', '0143/99682738', 22);\n\n/* PROJECTS */\nINSERT INTO project (id, version, identifier, name, company_id, volume, fixedPrice, debitor_id) VALUES (28, 0, '1000.2014.1', 'Webshop - Checkout Development', 19, 60, 15000, 20);\nINSERT INTO project (id, version, identifier, name, company_id, volume, hourlyRate) VALUES (29, 0, '1000.2013.1', 'Process automization', 19, 30, 80);\nINSERT INTO project (id, version, identifier, name, company_id, volume, dailyRate) VALUES (30, 0, '1002.2013.1', 'IaaS Java Development', 21, 100, 670);\nINSERT INTO project (id, version, identifier, name, company_id, volume, hourlyRate) VALUES (31, 0, '1002.2013.2', 'Test Manager', 21, 50, 85);\nINSERT INTO project (id, version, identifier, name, company_id, volume, hourlyRate) VALUES (32, 0, '1002.2014.1', 'Frontend Development', 21, 30, 70);\nINSERT INTO project (id, version, identifier, name, company_id, volume, hourlyRate, debitor_id) VALUES (33, 0, '1003.2014.1', 'ESB Architecture', 22, 90, 80, 20);\n\n/* TRAVEL EXPENSE REPORTS */\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (34, 0, 1, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (35, 0, 1, 'SUBMITTED', '2014-06-01 19:41:31', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (36, 0, 1, 'APPROVED', '2014-04-01 20:01:21', '2014-04-04 15:40:00', 8, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (37, 0, 1, 'REJECTED', '2014-05-01 17:45:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (38, 0, 2, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (39, 0, 2, 'SUBMITTED', '2014-06-01 13:30:21', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (40, 0, 2, 'APPROVED', '2014-04-01 13:30:21', '2014-04-06 08:30:12', 3, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (41, 0, 2, 'REJECTED', '2014-05-01 13:30:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (42, 0, 3, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (43, 0, 3, 'SUBMITTED', '2014-06-01 13:30:21', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (44, 0, 3, 'APPROVED', '2014-04-01 13:30:21', '2014-04-01 18:20:53', 1, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (45, 0, 3, 'REJECTED', '2014-05-01 13:30:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (46, 0, 4, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (47, 0, 4, 'SUBMITTED', '2014-06-01 13:30:21', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (48, 0, 4, 'APPROVED', '2014-04-01 13:30:21', '2014-04-05 14:00:12', 8, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (49, 0, 4, 'REJECTED', '2014-05-01 13:30:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (50, 0, 5, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (51, 0, 5, 'SUBMITTED', '2014-06-01 13:30:21', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (52, 0, 5, 'APPROVED', '2014-04-01 13:30:21', '2014-04-02 10:30:12', 7, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (53, 0, 5, 'REJECTED', '2014-05-01 13:30:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, debitor_id) VALUES (54, 0, 6, 'PENDING', 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (55, 0, 6, 'SUBMITTED', '2014-06-01 13:30:21', 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (56, 0, 6, 'APPROVED', '2014-04-01 13:30:21', '2014-04-02 10:30:12', 5, 21);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id) VALUES (57, 0, 6, 'REJECTED', '2014-05-01 13:30:21', 22);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (58, 0, 7, 'APPROVED', '2013-11-01 13:30:21', '2013-11-02 10:30:12', 8, 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (59, 0, 7, 'APPROVED', '2013-12-01 13:30:21', '2013-12-04 10:30:12', 8, 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (60, 0, 7, 'APPROVED', '2014-01-01 13:30:21', '2014-01-07 10:30:12', 8, 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (61, 0, 7, 'APPROVED', '2014-02-01 13:30:21', '2014-02-10 10:30:12', 8, 19);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (62, 0, 11, 'APPROVED', '2014-05-01 13:30:21', '2014-05-02 10:30:12', 8, 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (63, 0, 11, 'APPROVED', '2014-06-01 13:30:21', '2014-06-02 10:30:12', 8, 20);\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, approvalDate, approver_id, debitor_id) VALUES (64, 0, 11, 'APPROVED', '2014-07-01 13:30:21', '2014-07-02 10:30:12', 8, 20);\n\n\n/* WORKTIMES project 1000.2014.1 EMPLOYEE 1 */\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (1, 0, 28, 1, '2014-06-02', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (2, 0, 28, 1, '2014-06-03', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (3, 0, 28, 1, '2014-06-04', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (4, 0, 28, 1, '2014-06-05', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (5, 0, 28, 1, '2014-06-06', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (6, 0, 28, 1, '2014-06-09', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (7, 0, 28, 1, '2014-06-10', '09:00:00', '17:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (8, 0, 28, 1, '2014-06-11', '08:30:00', '16:45:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (9, 0, 28, 1, '2014-06-12', '10:30:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (10, 0, 28, 1, '2014-06-13', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (11, 0, 28, 1, '2014-06-16', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (12, 0, 28, 1, '2014-06-17', '08:30:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (13, 0, 28, 1, '2014-06-18', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (14, 0, 28, 1, '2014-06-19', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (15, 0, 28, 1, '2014-06-20', '08:00:00', '16:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (16, 0, 28, 1, '2014-06-24', '10:00:00', '17:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (17, 0, 28, 1, '2014-06-25', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (18, 0, 28, 1, '2014-06-26', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (19, 0, 28, 1, '2014-06-27', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (20, 0, 28, 1, '2014-06-28', '11:00:00', '18:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (21, 0, 28, 1, '2014-06-30', '12:00:00', '15:00:00');\n\n/* WORKTIMES project 1000.2014.1 EMPLOYEE 2 */\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (22, 0, 28, 2, '2014-06-02', '08:30:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (23, 0, 28, 2, '2014-06-03', '09:45:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (24, 0, 28, 2, '2014-06-04', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (25, 0, 28, 2, '2014-06-05', '10:15:00', '18:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (26, 0, 28, 2, '2014-06-06', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (27, 0, 28, 2, '2014-06-09', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (28, 0, 28, 2, '2014-06-10', '09:15:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (29, 0, 28, 2, '2014-06-11', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (30, 0, 28, 2, '2014-06-12', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (31, 0, 28, 2, '2014-06-13', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (32, 0, 28, 2, '2014-06-16', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (33, 0, 28, 2, '2014-06-17', '08:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (34, 0, 28, 2, '2014-06-18', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (35, 0, 28, 2, '2014-06-19', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (36, 0, 28, 2, '2014-06-20', '09:30:00', '16:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (37, 0, 28, 2, '2014-06-24', '09:00:00', '17:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (38, 0, 28, 2, '2014-06-25', '08:45:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (39, 0, 28, 2, '2014-06-26', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (40, 0, 28, 2, '2014-06-27', '09:45:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (41, 0, 28, 2, '2014-06-28', '09:00:00', '17:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (42, 0, 28, 2, '2014-06-30', '12:00:00', '15:00:00');\n\n/* WORKTIMES project 1002.2014.1 EMPLOYEE 3 */\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (43, 0, 32, 3, '2014-06-02', '12:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (44, 0, 32, 3, '2014-06-03', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (45, 0, 32, 3, '2014-06-04', '09:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (46, 0, 32, 3, '2014-06-05', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (47, 0, 32, 3, '2014-06-06', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (48, 0, 32, 3, '2014-06-09', '12:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (49, 0, 32, 3, '2014-06-10', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (50, 0, 32, 3, '2014-06-11', '07:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (51, 0, 32, 3, '2014-06-12', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (52, 0, 32, 3, '2014-06-13', '09:00:00', '16:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (53, 0, 32, 3, '2014-06-16', '13:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (54, 0, 32, 3, '2014-06-17', '08:00:00', '17:45:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (55, 0, 32, 3, '2014-06-18', '09:45:00', '18:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (56, 0, 32, 3, '2014-06-19', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (57, 0, 32, 3, '2014-06-20', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (58, 0, 32, 3, '2014-06-24', '11:00:00', '18:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (59, 0, 32, 3, '2014-06-25', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (60, 0, 32, 3, '2014-06-26', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (61, 0, 32, 3, '2014-06-27', '11:00:00', '19:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (62, 0, 32, 3, '2014-06-28', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (63, 0, 32, 3, '2014-06-30', '12:00:00', '17:00:00');\n\n/* WORKTIMES project 1002.2014.1 EMPLOYEE 4 */\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (64, 0, 32, 4, '2014-06-02', '11:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (65, 0, 32, 4, '2014-06-03', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (66, 0, 32, 4, '2014-06-04', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (67, 0, 32, 4, '2014-06-05', '10:15:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (68, 0, 32, 4, '2014-06-06', '07:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (69, 0, 32, 4, '2014-06-09', '12:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (70, 0, 32, 4, '2014-06-10', '08:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (71, 0, 32, 4, '2014-06-11', '07:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (72, 0, 32, 4, '2014-06-12', '09:00:00', '17:45:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (73, 0, 32, 4, '2014-06-13', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (74, 0, 32, 4, '2014-06-16', '13:00:00', '18:00:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (75, 0, 32, 4, '2014-06-17', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (76, 0, 32, 4, '2014-06-18', '09:00:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (77, 0, 32, 4, '2014-06-19', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (78, 0, 32, 4, '2014-06-20', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (79, 0, 32, 4, '2014-06-24', '11:00:00', '18:15:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (80, 0, 32, 4, '2014-06-25', '09:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (81, 0, 32, 4, '2014-06-26', '08:30:00', '16:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (82, 0, 32, 4, '2014-06-27', '10:00:00', '17:30:00');\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (83, 0, 32, 4, '2014-06-28', '09:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (84, 0, 32, 4, '2014-06-30', '12:00:00', '17:00:00');\n\n/* VACATION REQUESTS */\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (0, 0, 1, '2013-12-18', '2014-01-03', 10, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (1, 0, 1, '2014-07-10', '2014-07-18', 7, 'APPROVED', '2014-06-01 11:00:00', 2, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (2, 0, 1, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 5, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (3, 0, 2, '2013-12-19', '2014-01-03', 9, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (4, 0, 2, '2014-07-14', '2014-07-17', 4, 'APPROVED', '2014-06-01 11:00:00', 3, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (5, 0, 2, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 4, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (6, 0, 3, '2013-12-19', '2014-01-03', 9, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (7, 0, 3, '2014-07-10', '2014-07-18', 8, 'APPROVED', '2014-06-01 11:00:00', 1, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (8, 0, 3, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 6, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (9, 0, 4, '2013-12-19', '2014-01-03', 9, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (10, 0, 4, '2014-07-14', '2014-07-18', 5, 'APPROVED', '2014-06-01 11:00:00', 2, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (11, 0, 4, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 5, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (12, 0, 5, '2013-12-19', '2014-01-03', 9, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (13, 0, 5, '2014-07-14', '2014-07-15', 2, 'APPROVED', '2014-06-01 11:00:00', 1, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (14, 0, 5, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 1, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (15, 0, 6, '2013-12-19', '2014-01-03', 9, 'APPROVED', '2013-12-01 11:00:00', '2013-12-02 10:30:13');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (16, 0, 6, '2014-07-14', '2014-07-14', 1, 'APPROVED', '2014-06-01 11:00:00', 4, '2014-06-03 10:00:03');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (17, 0, 6, '2014-04-07', '2014-04-11', 5, 'REJECTED', '2014-03-15 11:00:00', 3, '2014-03-19 13:05:06');\n\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (18, 0, 9, '2014-04-24', '2014-04-29', 5, 'APPROVED', '2014-01-03 11:00:00', '2014-01-10 04:00:00');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approvalDate) VALUES (19, 0, 9, '2014-05-05', '2014-05-05', 1, 'APPROVED', '2014-04-01 10:00:00', '2014-04-08 04:00:00');\nINSERT INTO vacationRequest (id, version, employee_id, startDate, endDate, numberOfDays, status, submissionTime, approver_id, approvalDate) VALUES (20, 0, 9, '2014-06-17', '2014-06-24', 6, 'REJECTED', '2014-05-03 16:00:00', 1, '2014-05-03 16:10:01');\n\n\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (0, 0, 34, '2014-07-01', '2014-07-01', 31.34, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (1, 0, 34, '2014-07-01', '2014-07-04', 350, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (2, 0, 35, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (3, 0, 35, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (4, 0, 36, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (5, 0, 36, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (6, 0, 37, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (7, 0, 37, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (8, 0, 38, '2014-07-01', '2014-07-01', 15.16, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (9, 0, 38, '2014-07-01', '2014-07-04', 250, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (10, 0, 39, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (11, 0, 39, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (12, 0, 40, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (13, 0, 40, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (14, 0, 41, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (15, 0, 41, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (16, 0, 42, '2014-07-01', '2014-07-01', 131.34, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (17, 0, 42, '2014-07-01', '2014-07-04', 1350, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (18, 0, 43, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (19, 0, 43, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (20, 0, 44, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (21, 0, 44, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (22, 0, 45, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (23, 0, 45, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (24, 0, 46, '2014-07-01', '2014-07-01', 85.34, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (25, 0, 46, '2014-07-01', '2014-07-04', 250, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (26, 0, 47, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (27, 0, 47, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (28, 0, 48, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (29, 0, 48, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (30, 0, 49, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (31, 0, 49, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n \nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (32, 0, 50, '2014-07-01', '2014-07-01', 16.34, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (33, 0, 50, '2014-07-01', '2014-07-04', 370, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (34, 0, 51, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (35, 0, 51, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (36, 0, 52, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (37, 0, 52, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (38, 0, 53, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (39, 0, 53, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n \nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (40, 0, 54, '2014-07-01', '2014-07-01', 30.54, 19, '2014-04-16 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (41, 0, 54, '2014-07-01', '2014-07-04', 330, 19, '2014-07-16 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (42, 0, 55, '2014-06-02', '2014-06-02', 32.40, 19, '2014-07-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (43, 0, 55, '2014-06-02', '2014-06-05', 350, 19, '2014-07-01 12:40:51', 'HOTEL', true);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (44, 0, 56, '2014-04-01', '2014-04-10', 30.33, 19, '2014-05-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (45, 0, 56, '2014-04-01', '2014-04-10', 340, 19, '2014-05-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (46, 0, 57, '2014-05-01', '2014-05-10', 330.13, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (47, 0, 57, '2014-05-01', '2014-05-10', 1000, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n \nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (48, 0, 58, '2013-11-01', '2013-11-30', 210.31, 19, '2013-12-03 07:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (49, 0, 58, '2013-11-01', '2013-11-30', 2000, 19, '2013-12-03 07:01:44', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (50, 0, 59, '2013-12-01', '2013-12-24', 190.45, 19, '2013-12-26 07:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (51, 0, 59, '2013-12-01', '2013-12-24', 2100, 19, '2013-12-26 07:01:44', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (52, 0, 60, '2014-01-04', '2014-01-31', 250.99, 19, '2014-02-01 12:40:51', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (53, 0, 60, '2014-01-04', '2014-01-31', 1900, 19, '2014-02-01 12:40:51', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (54, 0, 61, '2014-02-01', '2014-02-28', 150.56, 19, '2014-04-01 08:31:12', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (55, 0, 61, '2014-02-01', '2014-02-28', 1500, 19, '2014-04-01 08:33:12', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (56, 0, 62, '2014-05-01', '2014-05-31', 450, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (57, 0, 62, '2014-05-01', '2014-05-31', 2030, 19, '2014-06-01 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (58, 0, 63, '2014-06-01', '2014-06-30', 390, 19, '2014-07-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (59, 0, 63, '2014-06-01', '2014-06-30', 3000, 19, '2014-07-01 10:00:30', 'HOTEL', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (60, 0, 64, '2014-07-01', '2014-07-31', 200, 19, '2014-06-01 10:00:30', 'TAXI', false);\nINSERT INTO travelExpense (id, version, report_id, fromDate, toDate, cost, vat, submissionDate, type, paid) VALUES (61, 0, 64, '2014-07-01', '2014-07-31', 1500, 19, '2014-06-01 10:00:30', 'HOTEL', false);\n\n/* BILLABLE TIMES */\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (0, 0, 1, 28, '2014-06-02', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (1, 0, 1, 28, '2014-06-03', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (2, 0, 1, 28, '2014-06-04', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (3, 0, 1, 28, '2014-06-05', 450);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (4, 0, 1, 28, '2014-06-06', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (5, 0, 1, 28, '2014-06-09', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (6, 0, 1, 28, '2014-06-10', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (7, 0, 1, 28, '2014-06-11', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (8, 0, 1, 28, '2014-06-12', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (9, 0, 1, 28, '2014-06-13', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (10, 0, 1, 28, '2014-06-16', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (11, 0, 1, 28, '2014-06-17', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (12, 0, 1, 28, '2014-06-18', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (13, 0, 1, 28, '2014-06-19', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (14, 0, 1, 28, '2014-06-20', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (15, 0, 1, 28, '2014-06-24', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (16, 0, 1, 28, '2014-06-25', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (17, 0, 1, 28, '2014-06-26', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (18, 0, 1, 28, '2014-06-27', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (19, 0, 1, 28, '2014-06-28', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (20, 0, 1, 28, '2014-06-30', 480);\n \nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (21, 0, 2, 28, '2014-06-02', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (22, 0, 2, 28, '2014-06-03', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (23, 0, 2, 28, '2014-06-04', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (24, 0, 2, 28, '2014-06-05', 450);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (25, 0, 2, 28, '2014-06-06', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (26, 0, 2, 28, '2014-06-09', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (27, 0, 2, 28, '2014-06-10', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (28, 0, 2, 28, '2014-06-11', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (29, 0, 2, 28, '2014-06-12', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (30, 0, 2, 28, '2014-06-13', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (31, 0, 2, 28, '2014-06-16', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (32, 0, 2, 28, '2014-06-17', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (33, 0, 2, 28, '2014-06-18', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (34, 0, 2, 28, '2014-06-19', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (35, 0, 2, 28, '2014-06-20', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (36, 0, 2, 28, '2014-06-24', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (37, 0, 2, 28, '2014-06-25', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (38, 0, 2, 28, '2014-06-26', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (39, 0, 2, 28, '2014-06-27', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (40, 0, 2, 28, '2014-06-28', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (41, 0, 2, 28, '2014-06-30', 480);\n \nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (42, 0, 3, 32, '2014-06-02', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (43, 0, 3, 32, '2014-06-03', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (44, 0, 3, 32, '2014-06-04', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (45, 0, 3, 32, '2014-06-05', 450);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (46, 0, 3, 32, '2014-06-06', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (47, 0, 3, 32, '2014-06-09', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (48, 0, 3, 32, '2014-06-10', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (49, 0, 3, 32, '2014-06-11', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (50, 0, 3, 32, '2014-06-12', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (51, 0, 3, 32, '2014-06-13', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (52, 0, 3, 32, '2014-06-16', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (53, 0, 3, 32, '2014-06-17', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (54, 0, 3, 32, '2014-06-18', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (55, 0, 3, 32, '2014-06-19', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (56, 0, 3, 32, '2014-06-20', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (57, 0, 3, 32, '2014-06-24', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (58, 0, 3, 32, '2014-06-25', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (59, 0, 3, 32, '2014-06-26', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (60, 0, 3, 32, '2014-06-27', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (61, 0, 3, 32, '2014-06-28', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (62, 0, 3, 32, '2014-06-30', 480);\n \nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (63, 0, 4, 32, '2014-06-02', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (64, 0, 4, 32, '2014-06-03', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (65, 0, 4, 32, '2014-06-04', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (66, 0, 4, 32, '2014-06-05', 450);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (67, 0, 4, 32, '2014-06-06', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (68, 0, 4, 32, '2014-06-09', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (69, 0, 4, 32, '2014-06-10', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (70, 0, 4, 32, '2014-06-11', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (71, 0, 4, 32, '2014-06-12', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (72, 0, 4, 32, '2014-06-13', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (73, 0, 4, 32, '2014-06-16', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (74, 0, 4, 32, '2014-06-17', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (75, 0, 4, 32, '2014-06-18', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (76, 0, 4, 32, '2014-06-19', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (77, 0, 4, 32, '2014-06-20', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (78, 0, 4, 32, '2014-06-24', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (79, 0, 4, 32, '2014-06-25', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (80, 0, 4, 32, '2014-06-26', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (81, 0, 4, 32, '2014-06-27', 480);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (82, 0, 4, 32, '2014-06-28', 360);\nINSERT INTO billableTime (id, version, employee, project, date, minutes) VALUES (83, 0, 4, 32, '2014-06-30', 480);\n\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (0, 0, '1003.2014.1-2014.01-1', 22, '2014-01-04', 1500.00, 'PAID', '2014-02-01');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (1, 0, '1003.2014.1-2014.01-2', 22, '2014-01-04', 2300.00, 'PAID', '2014-02-01');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (2, 0, '1003.2014.1-2014.01-3', 22, '2014-01-04', 6000.00, 'PAID', '2014-02-01');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (3, 0, '1003.2014.1-2014.02-1', 22, '2014-02-15', 3000.00, 'PAID', '2014-03-20');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (4, 0, '1003.2014.1-2014.02-2', 22, '2014-02-15', 4020.00, 'PAID', '2014-03-20');\n\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (5, 0, '1000.2014.1-2014.01-1', 19, '2014-01-15', 12570.00, 'PAID', '2014-03-01');\n\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (6, 0, '1000.2014.1-2014.06-1', 20, '2014-06-03', 7400.00, 'PAID', '2014-07-01');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (7, 0, '1000.2014.1-2014.06-2', 20, '2014-06-03', 7600.00, 'PAID', '2014-07-01');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (8, 0, '1002.2014.1-2014.06-1', 21, '2014-06-01', 13000.00, 'PAID', '2014-06-15');\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (9, 0, '1002.2014.1-2014.06-2', 21, '2014-06-01', 25100.00, 'PAID', '2014-07-15');\n"
  },
  {
    "path": "src/main/resources/db/migration/V10__modify_travel_expense_add_comment.sql",
    "content": "alter table TravelExpense\n  add column comment varchar(255);\n"
  },
  {
    "path": "src/main/resources/db/migration/V11__add_travel_expense_report_comments.sql",
    "content": "create table TravelExpenseReportComment (\n  id int8 not null,\n  submissionDate timestamp,\n  text varchar(255),\n  employee_id int8,\n  travelExpenseReport_id int8,\n  primary key (id)\n);\n\nalter table TravelExpenseReportComment\n  add constraint FKCEF7236D55198E9B\n  foreign key (employee_id)\n  references Employee;\n\nalter table TravelExpenseReportComment\n  add constraint FKCEF7236D6F1C4208\n  foreign key (travelExpenseReport_id)\n  references TravelExpenseReport;"
  },
  {
    "path": "src/main/resources/db/migration/V12__modify_company_add_time_for_payment.sql",
    "content": "alter table Company\n  add column timeForPayment int4;"
  },
  {
    "path": "src/main/resources/db/migration/V13__modify_travel_expense_reports_add_debitor_and_project.sql",
    "content": "alter table TravelExpenseReport\n  add column debitor_id int8 not null default 0;\n\nupdate TravelExpenseReport set debitor_id = (\n    select id from Company where companyId = '1000'\n);\n\nalter table TravelExpenseReport\n    alter column debitor_id drop default;\n\nalter table TravelExpenseReport\n  add column project_id int8;\n\nalter table TravelExpenseReport\n  add constraint FK854DBA92D4C285A6\n  foreign key (project_id)\n  references Project;\n\nalter table TravelExpenseReport\n  add constraint FK854DBA92F02B33F8\n  foreign key (debitor_id)\n  references Company;"
  },
  {
    "path": "src/main/resources/db/migration/V14__add_uuid_mapping.sql",
    "content": "CREATE TABLE uuid_mapping (\n  id int8 not null,\n  uuid varchar(40)\n);"
  },
  {
    "path": "src/main/resources/db/migration/V15__migrate_credentials.sql",
    "content": "ALTER TABLE Employee\n  ADD COLUMN email VARCHAR(255);\n\nALTER TABLE Employee\n    ADD UNIQUE (email);\n\n-- transfer the email to the employee\nUPDATE Employee e SET email = (SELECT email FROM Credential WHERE id = e.id);\n\nALTER TABLE Employee\n    ALTER COLUMN email SET NOT NULL;\n\nCREATE TABLE Settings (\n    id INT8 NOT NULL,\n    type VARCHAR(255),\n    value VARCHAR(255) NOT NULL,\n    employee_id INT8 NOT NULL,\n    PRIMARY KEY (id)\n);\n\nalter table Settings add constraint FK_18fk82qvt48n13545pq4dt2fr foreign key (employee_id) references Employee;\n\n\n-- transfer locale setting from credential to settins\nINSERT INTO Settings (id, type, value, employee_id) (\n  SELECT nextval('hibernate_sequence'), 'LOCALE', locale, id FROM Credential\n);\n\nDROP TABLE credential_authority;\nDROP TABLE credential;\nDROP TABLE authority;\n"
  },
  {
    "path": "src/main/resources/db/migration/V16__add_holidays_2015.sql",
    "content": "insert into holiday (id, day, name, federalstate) values (167, '2014-12-24', 'Weihnachten', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (168, '2014-12-24', 'Weihnachten', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (169, '2014-12-24', 'Weihnachten', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (170, '2014-12-24', 'Weihnachten', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (171, '2014-12-24', 'Weihnachten', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (172, '2014-12-24', 'Weihnachten', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (173, '2014-12-24', 'Weihnachten', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (174, '2014-12-24', 'Weihnachten', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (175, '2014-12-24', 'Weihnachten', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (176, '2014-12-24', 'Weihnachten', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (177, '2014-12-24', 'Weihnachten', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (178, '2014-12-24', 'Weihnachten', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (179, '2014-12-24', 'Weihnachten', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (180, '2014-12-24', 'Weihnachten', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (181, '2014-12-24', 'Weihnachten', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (182, '2014-12-24', 'Weihnachten', 'THUERINGEN');\n\ninsert into holiday (id, day, name, federalstate) values (183, '2014-12-31', 'Silvester', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (184, '2014-12-31', 'Silvester', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (185, '2014-12-31', 'Silvester', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (186, '2014-12-31', 'Silvester', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (187, '2014-12-31', 'Silvester', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (188, '2014-12-31', 'Silvester', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (189, '2014-12-31', 'Silvester', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (190, '2014-12-31', 'Silvester', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (191, '2014-12-31', 'Silvester', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (192, '2014-12-31', 'Silvester', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (193, '2014-12-31', 'Silvester', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (194, '2014-12-31', 'Silvester', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (195, '2014-12-31', 'Silvester', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (196, '2014-12-31', 'Silvester', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (197, '2014-12-31', 'Silvester', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (198, '2014-12-31', 'Silvester', 'THUERINGEN');\n"
  },
  {
    "path": "src/main/resources/db/migration/V17__add_holidays_2015.sql",
    "content": "-- 2015 - Baden Württemberg\ninsert into holiday (id, day, name, federalstate) values (199, '2015-01-01', 'Neujahr', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (200, '2015-01-06', 'Heilige Drei Könige', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (201, '2015-04-03', 'Karfreitag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (202, '2015-04-06', 'Ostermontag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (203, '2015-05-01', 'Tag der Arbeit', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (204, '2015-05-14', 'Christi Himmelfahrt', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (205, '2015-05-25', 'Pfingstmontag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (206, '2015-06-04', 'Fronleichnam', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (207, '2015-10-03', 'Tag der Deutschen Einheit', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (208, '2015-11-01', 'Allerheiligen', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (209, '2015-12-24', 'Weihnachten', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (210, '2015-12-25', '1. Weihnachtstag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (211, '2015-12-26', '2. Weihnachtstag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (212, '2015-12-31', 'Silvester', 'BADEN_WUERTTEMBERG');\n\n-- 2015 - Bayern\ninsert into holiday (id, day, name, federalstate) values (213, '2015-01-01', 'Neujahr', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (214, '2015-01-06', 'Heilige Drei Könige', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (215, '2015-04-03', 'Karfreitag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (216, '2015-04-06', 'Ostermontag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (217, '2015-05-01', 'Tag der Arbeit', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (218, '2015-05-14', 'Christi Himmelfahrt', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (219, '2015-05-25', 'Pfingstmontag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (220, '2015-06-04', 'Fronleichnam', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (221, '2015-08-15', 'Mariä Himmelfahrt', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (222, '2015-10-03', 'Tag der Deutschen Einheit', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (223, '2015-11-01', 'Allerheiligen', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (224, '2015-12-24', 'Weihnachten', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (225, '2015-12-25', '1. Weihnachtstag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (226, '2015-12-26', '2. Weihnachtstag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (227, '2015-12-31', 'Silvester', 'BAYERN');\n\n-- 2015 - Berlin\ninsert into holiday (id, day, name, federalstate) values (228, '2015-01-01', 'Neujahr', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (229, '2015-04-03', 'Karfreitag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (230, '2015-04-06', 'Ostermontag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (231, '2015-05-01', 'Tag der Arbeit', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (232, '2015-05-14', 'Christi Himmelfahrt', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (233, '2015-05-25', 'Pfingstmontag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (234, '2015-10-03', 'Tag der Deutschen Einheit', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (235, '2015-12-24', 'Weihnachten', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (236, '2015-12-25', '1. Weihnachtstag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (237, '2015-12-26', '2. Weihnachtstag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (238, '2015-12-31', 'Silvester', 'BERLIN');\n\n-- 2015 - Brandenburg\ninsert into holiday (id, day, name, federalstate) values (239, '2015-01-01', 'Neujahr', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (240, '2015-04-03', 'Karfreitag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (241, '2015-04-06', 'Ostermontag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (242, '2015-05-01', 'Tag der Arbeit', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (243, '2015-05-14', 'Christi Himmelfahrt', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (244, '2015-05-25', 'Pfingstmontag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (245, '2015-10-03', 'Tag der Deutschen Einheit', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (246, '2015-10-31', 'Reformationstag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (247, '2015-12-24', 'Weihnachten', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (248, '2015-12-25', '1. Weihnachtstag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (249, '2015-12-26', '2. Weihnachtstag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (250, '2015-12-31', 'Silvester', 'BRANDENBURG');\n\n-- 2015 - Bremen\ninsert into holiday (id, day, name, federalstate) values (251, '2015-01-01', 'Neujahr', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (252, '2015-04-03', 'Karfreitag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (253, '2015-04-06', 'Ostermontag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (254, '2015-05-01', 'Tag der Arbeit', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (255, '2015-05-14', 'Christi Himmelfahrt', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (256, '2015-05-25', 'Pfingstmontag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (257, '2015-10-03', 'Tag der Deutschen Einheit', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (258, '2015-12-24', 'Weihnachten', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (259, '2015-12-25', '1. Weihnachtstag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (260, '2015-12-26', '2. Weihnachtstag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (261, '2015-12-31', 'Silvester', 'BREMEN');\n\n-- 2015 - Hamburg\ninsert into holiday (id, day, name, federalstate) values (262, '2015-01-01', 'Neujahr', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (263, '2015-04-03', 'Karfreitag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (264, '2015-04-06', 'Ostermontag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (265, '2015-05-01', 'Tag der Arbeit', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (266, '2015-05-14', 'Christi Himmelfahrt', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (267, '2015-05-25', 'Pfingstmontag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (268, '2015-10-03', 'Tag der Deutschen Einheit', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (269, '2015-12-24', 'Weihnachten', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (270, '2015-12-25', '1. Weihnachtstag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (271, '2015-12-26', '2. Weihnachtstag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (272, '2015-12-31', 'Silvester', 'HAMBURG');\n\n-- 2015 - Hessen\ninsert into holiday (id, day, name, federalstate) values (273, '2015-01-01', 'Neujahr', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (274, '2015-04-03', 'Karfreitag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (275, '2015-04-06', 'Ostermontag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (276, '2015-05-01', 'Tag der Arbeit', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (277, '2015-05-14', 'Christi Himmelfahrt', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (278, '2015-05-25', 'Pfingstmontag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (279, '2015-06-04', 'Fronleichnam', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (280, '2015-10-03', 'Tag der Deutschen Einheit', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (281, '2015-12-24', 'Weihnachten', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (282, '2015-12-25', '1. Weihnachtstag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (283, '2015-12-26', '2. Weihnachtstag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (284, '2015-12-31', 'Silvester', 'HESSEN');\n\n-- 2015 - Mecklenburg-Vorpommern\ninsert into holiday (id, day, name, federalstate) values (285, '2015-01-01', 'Neujahr', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (286, '2015-04-03', 'Karfreitag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (287, '2015-04-06', 'Ostermontag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (288, '2015-05-01', 'Tag der Arbeit', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (289, '2015-05-14', 'Christi Himmelfahrt', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (290, '2015-05-25', 'Pfingstmontag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (291, '2015-10-03', 'Tag der Deutschen Einheit', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (292, '2015-10-31', 'Reformationstag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (293, '2015-12-24', 'Weihnachten', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (294, '2015-12-25', '1. Weihnachtstag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (295, '2015-12-26', '2. Weihnachtstag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (296, '2015-12-31', 'Silvester', 'MECKLENBURG_VORPOMMERN');\n\n-- 2015 - Niedersachsen\ninsert into holiday (id, day, name, federalstate) values (297, '2015-01-01', 'Neujahr', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (298, '2015-04-03', 'Karfreitag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (299, '2015-04-06', 'Ostermontag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (300, '2015-05-01', 'Tag der Arbeit', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (301, '2015-05-14', 'Christi Himmelfahrt', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (302, '2015-05-25', 'Pfingstmontag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (303, '2015-10-03', 'Tag der Deutschen Einheit', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (304, '2015-12-24', 'Weihnachten', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (305, '2015-12-25', '1. Weihnachtstag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (306, '2015-12-26', '2. Weihnachtstag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (307, '2015-12-31', 'Silvester', 'NIEDERSACHSEN');\n\n-- 2015 - Nordrhein-Westfalen\ninsert into holiday (id, day, name, federalstate) values (308,  '2015-01-01', 'Neujahr', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (309,  '2015-04-03', 'Karfreitag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (310,  '2015-04-06', 'Ostermontag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (311,  '2015-05-01', 'Tag der Arbeit', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (312,  '2015-05-14', 'Christi Himmelfahrt', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (313,  '2015-05-25', 'Pfingstmontag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (314,  '2015-06-04', 'Fronleichnam', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (315,  '2015-10-03', 'Tag der Deutschen Einheit', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (316, '2015-11-01', 'Allerheiligen', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (317, '2015-12-24', 'Weihnachten', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (318, '2015-12-25', '1. Weihnachtstag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (319, '2015-12-26', '2. Weihnachtstag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (320, '2015-12-31', 'Silvester', 'NORDRHEIN_WESTFALEN');\n\n-- 2015 - Rheinland-Pfalz\ninsert into holiday (id, day, name, federalstate) values (321, '2015-01-01', 'Neujahr', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (322, '2015-04-03', 'Karfreitag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (323, '2015-04-06', 'Ostermontag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (324, '2015-05-01', 'Tag der Arbeit', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (325, '2015-05-14', 'Christi Himmelfahrt', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (326, '2015-05-25', 'Pfingstmontag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (327, '2015-06-04', 'Fronleichnam', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (328, '2015-10-03', 'Tag der Deutschen Einheit', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (329, '2015-11-01', 'Allerheiligen', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (330, '2015-12-24', 'Weihnachten', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (331, '2015-12-25', '1. Weihnachtstag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (332, '2015-12-26', '2. Weihnachtstag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (333, '2015-12-31', 'Silvester', 'RHEINLAND_PFALZ');\n\n-- 2015 - Saarland\ninsert into holiday (id, day, name, federalstate) values (334, '2015-01-01', 'Neujahr', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (335, '2015-04-03', 'Karfreitag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (336, '2015-04-06', 'Ostermontag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (337, '2015-05-01', 'Tag der Arbeit', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (338, '2015-05-14', 'Christi Himmelfahrt', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (339, '2015-05-25', 'Pfingstmontag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (340, '2015-06-04', 'Fronleichnam', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (341, '2015-08-15', 'Mariä Himmelfahrt', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (342, '2015-10-03', 'Tag der Deutschen Einheit', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (343, '2015-11-01', 'Allerheiligen', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (344, '2015-12-24', 'Weihnachten', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (345, '2015-12-25', '1. Weihnachtstag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (346, '2015-12-26', '2. Weihnachtstag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (347, '2015-12-31', 'Silvester', 'SAARLAND');\n\n-- 2015 - Sachsen\ninsert into holiday (id, day, name, federalstate) values (348, '2015-01-01', 'Neujahr', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (349, '2015-04-03', 'Karfreitag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (350, '2015-04-06', 'Ostermontag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (351, '2015-05-01', 'Tag der Arbeit', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (352, '2015-05-14', 'Christi Himmelfahrt', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (353, '2015-05-25', 'Pfingstmontag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (354, '2015-10-03', 'Tag der Deutschen Einheit', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (355, '2015-10-31', 'Reformationstag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (356, '2015-11-18', 'Buß- und Bettag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (357, '2015-12-24', 'Weihnachten', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (358, '2015-12-25', '1. Weihnachtstag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (359, '2015-12-26', '2. Weihnachtstag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (360, '2015-12-31', 'Silvester', 'SACHSEN');\n\n-- 2015 - Sachsen-Anhalt\ninsert into holiday (id, day, name, federalstate) values (361, '2015-01-01', 'Neujahr', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (362, '2015-01-06', 'Heilige Drei Könige', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (363, '2015-04-03', 'Karfreitag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (364, '2015-04-06', 'Ostermontag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (365, '2015-05-01', 'Tag der Arbeit', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (366, '2015-05-14', 'Christi Himmelfahrt', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (367, '2015-05-25', 'Pfingstmontag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (368, '2015-10-03', 'Tag der Deutschen Einheit', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (369, '2015-10-31', 'Reformationstag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (370, '2015-12-24', 'Weihnachten', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (371, '2015-12-25', '1. Weihnachtstag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (372, '2015-12-26', '2. Weihnachtstag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (373, '2015-12-31', 'Silvester', 'SACHSEN_ANHALT');\n\n-- 2015 - Schleswig-Holstein\ninsert into holiday (id, day, name, federalstate) values (374, '2015-01-01', 'Neujahr', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (375, '2015-04-03', 'Karfreitag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (376, '2015-04-06', 'Ostermontag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (377, '2015-05-01', 'Tag der Arbeit', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (378, '2015-05-14', 'Christi Himmelfahrt', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (379, '2015-05-25', 'Pfingstmontag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (380, '2015-10-03', 'Tag der Deutschen Einheit', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (381, '2015-12-24', 'Weihnachten', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (382, '2015-12-25', '1. Weihnachtstag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (383, '2015-12-26', '2. Weihnachtstag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (384, '2015-12-31', 'Silvester', 'SCHLESWIG_HOLSTEIN');\n\n-- 2015 - Thüringen\ninsert into holiday (id, day, name, federalstate) values (385, '2015-01-01', 'Neujahr', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (386, '2015-04-03', 'Karfreitag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (387, '2015-04-06', 'Ostermontag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (388, '2015-05-01', 'Tag der Arbeit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (389, '2015-05-14', 'Christi Himmelfahrt', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (390, '2015-05-25', 'Pfingstmontag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (391, '2015-10-03', 'Tag der Deutschen Einheit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (392, '2015-10-31', 'Tag der Deutschen Einheit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (393, '2015-12-24', 'Weihnachten', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (394, '2015-12-25', 'Reformationstag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (395, '2015-12-26', '2. Weihnachtstag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (396, '2015-12-31', 'Silvester', 'THUERINGEN');\n\n-- 2016 - new years eve\ninsert into holiday (id, day, name, federalstate) values (397, '2016-01-01', 'Neujahr', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (398, '2016-01-01', 'Neujahr', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (399, '2016-01-01', 'Neujahr', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (400, '2016-01-01', 'Neujahr', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (401, '2016-01-01', 'Neujahr', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (402, '2016-01-01', 'Neujahr', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (403, '2016-01-01', 'Neujahr', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (404, '2016-01-01', 'Neujahr', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (405, '2016-01-01', 'Neujahr', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (406, '2016-01-01', 'Neujahr', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (407, '2016-01-01', 'Neujahr', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (408, '2016-01-01', 'Neujahr', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (409, '2016-01-01', 'Neujahr', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (410, '2016-01-01', 'Neujahr', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (411, '2016-01-01', 'Neujahr', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (412, '2016-01-01', 'Neujahr', 'THUERINGEN');\n\n-- 2016 - three kings\ninsert into holiday (id, day, name, federalstate) values (413, '2016-01-06', 'Heilige Drei Könige', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (414, '2016-01-06', 'Heilige Drei Könige', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (415, '2016-01-06', 'Heilige Drei Könige', 'SACHSEN_ANHALT');\n\n\n"
  },
  {
    "path": "src/main/resources/db/migration/V18__expense_paid_marker.sql",
    "content": "ALTER TABLE travelexpense ADD COLUMN paid BOOLEAN DEFAULT false;"
  },
  {
    "path": "src/main/resources/db/migration/V19__add_employee_address.sql",
    "content": "ALTER TABLE employee ADD COLUMN address_id int8;\nALTER TABLE employee ADD CONSTRAINT employee_contact_address FOREIGN KEY (address_id) REFERENCES address;\n"
  },
  {
    "path": "src/main/resources/db/migration/V1__create_schema.sql",
    "content": "    create table Address (\n        id int8 not null,\n        city varchar(255),\n        country varchar(255),\n        houseNumber varchar(255),\n        street varchar(255),\n        version int4,\n        zipCode varchar(255),\n        primary key (id)\n    );\n\n    create table Authority (\n        id int8 not null,\n        authority varchar(255) unique,\n        authorityOrder int4,\n        primary key (id)\n    );\n\n    create table BillableTime (\n        id int8 not null,\n        date date,\n        minutes int4,\n        version int4,\n        employee int8,\n        project int8,\n        primary key (id),\n        unique (employee, project, date)\n    );\n\n    create table Company (\n        id int8 not null,\n        companyId int8 unique,\n        name varchar(255),\n        version int4,\n        address_id int8,\n        primary key (id)\n    );\n\n    create table ContactPerson (\n        id int8 not null,\n        email varchar(255),\n        firstName varchar(255),\n        lastName varchar(255),\n        phone varchar(255),\n        salutation varchar(255),\n        version int4,\n        company int8,\n        primary key (id)\n    );\n\n    create table Credential (\n        id int8 not null,\n        email varchar(255) unique,\n        enabled boolean,\n        locale varchar(255),\n        primary key (id)\n    );\n\n    create table Credential_Authority (\n        Credential_id int8 not null,\n        authorities_id int8 not null\n    );\n\n    create table Employee (\n        id int8 not null,\n        federalState varchar(255),\n        firstName varchar(255),\n        hourlyCostRate numeric(19, 2),\n        joinDate date,\n        lastName varchar(255),\n        leaveDate date,\n        phoneNumber varchar(255),\n        salary numeric(19, 2),\n        title varchar(255),\n        vacationEntitlement float4,\n        version int4,\n        primary key (id)\n    );\n\n    create table Holiday (\n        id int8 not null,\n        day date,\n        federalState varchar(255),\n        name varchar(255),\n        primary key (id)\n    );\n\n    create table Project (\n        id int8 not null,\n        dailyRate numeric(19, 2),\n        fixedPrice numeric(19, 2),\n        hourlyRate numeric(19, 2),\n        identifier varchar(255) unique,\n        name varchar(255),\n        version int4,\n        volume int4,\n        company_id int8,\n        debitor_id int8,\n        primary key (id)\n    );\n\n    create table VacationRequest (\n        id int8 not null,\n        approvalDate date,\n        endDate date,\n        numberOfDays int4,\n        startDate date,\n        status varchar(255),\n        submissionTime timestamp,\n        version int4,\n        approver_id int8,\n        employee_id int8,\n        primary key (id)\n    );\n\n    create table WorkTime (\n        id int8 not null,\n        comment varchar(255),\n        date date,\n        endTime time,\n        startTime time,\n        version int4,\n        employee int8,\n        project int8,\n        primary key (id)\n    );\n\n     create table TravelExpense (\n        id int8 not null,\n        cost numeric(19, 2),\n        fromDate date,\n        submissionDate timestamp,\n        toDate date,\n        type varchar(255),\n        vat numeric(19, 2),\n        version int4,\n        report_id int8,\n        primary key (id)\n    );\n\n    create table TravelExpenseReport (\n        id int8 not null,\n        status varchar(255),\n        version int4,\n        employee_id int8,\n        primary key (id)\n    );\n\n    alter table BillableTime\n        add constraint FK3EBA06E37BE2CBE\n        foreign key (project)\n        references Project;\n\n    alter table BillableTime\n        add constraint FK3EBA06E65C090FD\n        foreign key (employee)\n        references Employee;\n\n    alter table Company\n        add constraint FK9BDFD45D9475612A\n        foreign key (address_id)\n        references Address;\n\n    alter table ContactPerson\n        add constraint FK4E7B4375FA3D5CEA\n        foreign key (company)\n        references Company;\n\n    alter table Credential_Authority\n        add constraint FK3DA6FD5B34EFD736\n        foreign key (authorities_id)\n        references Authority;\n\n    alter table Credential_Authority\n        add constraint FK3DA6FD5B27F2CCA0\n        foreign key (Credential_id)\n        references Credential;\n\n    alter table Project\n        add constraint FK50C8E2F98F0FA88A\n        foreign key (company_id)\n        references Company;\n\n    alter table Project\n        add constraint FK50C8E2F9F02B33F8\n        foreign key (debitor_id)\n        references Company;\n\n    alter table VacationRequest\n        add constraint FK266F9CD248918324\n        foreign key (approver_id)\n        references Employee;\n\n    alter table VacationRequest\n        add constraint FK266F9CD255198E9B\n        foreign key (employee_id)\n        references Employee;\n\n    alter table WorkTime\n        add constraint FK5EE019E37BE2CBE\n        foreign key (project)\n        references Project;\n\n    alter table WorkTime\n        add constraint FK5EE019E65C090FD\n        foreign key (employee)\n        references Employee;\n\n    alter table TravelExpense\n        add constraint FK1BC7BFBE1E281C46\n        foreign key (report_id)\n        references TravelExpenseReport;\n\n    alter table TravelExpenseReport\n        add constraint FK854DBA9255198E9B\n        foreign key (employee_id)\n        references Employee;\n\n    create sequence hibernate_sequence;\n\n"
  },
  {
    "path": "src/main/resources/db/migration/V20__add_employe_deleted.sql",
    "content": "ALTER TABLE employee ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT FALSE;"
  },
  {
    "path": "src/main/resources/db/migration/V2__add_roles.sql",
    "content": "insert into employee (id, version, firstName, lastName, title, hourlyCostRate, salary, federalState) values (0, 0, 'admin', 'admin', '', 0, 0, 'BERLIN');\ninsert into credential (id, email, enabled, locale) values (0, 'admin@techdev.de', true, 'en');\ninsert into authority (id, authority, authorityOrder) values (0, 'ROLE_ADMIN', 0);\ninsert into authority (id, authority, authorityOrder) values (1, 'ROLE_SUPERVISOR', 1);\ninsert into authority (id, authority, authorityOrder) values (2, 'ROLE_EMPLOYEE', 2);\ninsert into credential_authority (credential_id, authorities_id) values (0, 0);\n\n"
  },
  {
    "path": "src/main/resources/db/migration/V3__add_holidays_2014.sql",
    "content": "-- CLean-up\ndelete from holiday;\n\n-- 2014 - Baden Württemberg\ninsert into holiday (id, day, name, federalstate) values (1,  '2014-01-01', 'Neujahr', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (2,  '2014-01-06', 'Heilige Drei Könige', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (3,  '2014-04-18', 'Karfreitag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (4,  '2014-04-21', 'Ostermontag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (5,  '2014-05-01', 'Tag der Arbeit', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (6,  '2014-05-29', 'Christi Himmelfahrt', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (7,  '2014-06-09', 'Pfingstmontag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (8,  '2014-06-19', 'Fronleichnam', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (9,  '2014-10-03', 'Tag der Deutschen Einheit', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (10, '2014-11-01', 'Allerheiligen', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (11, '2014-12-25', '1. Weihnachtstag', 'BADEN_WUERTTEMBERG');\ninsert into holiday (id, day, name, federalstate) values (12, '2014-12-26', '2. Weihnachtstag', 'BADEN_WUERTTEMBERG');\n\n-- 2014 - Bayern\ninsert into holiday (id, day, name, federalstate) values (13, '2014-01-01', 'Neujahr', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (14, '2014-01-06', 'Heilige Drei Könige', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (15, '2014-04-18', 'Karfreitag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (16, '2014-04-21', 'Ostermontag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (17, '2014-05-01', 'Tag der Arbeit', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (18, '2014-05-29', 'Christi Himmelfahrt', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (19, '2014-06-09', 'Pfingstmontag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (20, '2014-06-19', 'Fronleichnam', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (21, '2014-08-15', 'Mariä Himmelfahrt', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (22, '2014-10-03', 'Tag der Deutschen Einheit', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (23, '2014-11-01', 'Allerheiligen', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (24, '2014-12-25', '1. Weihnachtstag', 'BAYERN');\ninsert into holiday (id, day, name, federalstate) values (25, '2014-12-26', '2. Weihnachtstag', 'BAYERN');\n\n-- 2014 - Berlin\ninsert into holiday (id, day, name, federalstate) values (26, '2014-01-01', 'Neujahr', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (27, '2014-04-18', 'Karfreitag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (28, '2014-04-21', 'Ostermontag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (29, '2014-05-01', 'Tag der Arbeit', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (30, '2014-05-29', 'Christi Himmelfahrt', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (31, '2014-06-09', 'Pfingstmontag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (32, '2014-10-03', 'Tag der Deutschen Einheit', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (33, '2014-12-25', '1. Weihnachtstag', 'BERLIN');\ninsert into holiday (id, day, name, federalstate) values (34, '2014-12-26', '2. Weihnachtstag', 'BERLIN');\n\n-- 2014 - Brandenburg\ninsert into holiday (id, day, name, federalstate) values (35, '2014-01-01', 'Neujahr', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (36, '2014-04-18', 'Karfreitag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (37, '2014-04-21', 'Ostermontag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (38, '2014-05-01', 'Tag der Arbeit', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (39, '2014-05-29', 'Christi Himmelfahrt', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (40, '2014-06-09', 'Pfingstmontag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (41, '2014-10-03', 'Tag der Deutschen Einheit', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (42, '2014-10-31', 'Reformationstag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (43, '2014-12-25', '1. Weihnachtstag', 'BRANDENBURG');\ninsert into holiday (id, day, name, federalstate) values (44, '2014-12-26', '2. Weihnachtstag', 'BRANDENBURG');\n\n-- 2014 - Bremen\ninsert into holiday (id, day, name, federalstate) values (45, '2014-01-01', 'Neujahr', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (46, '2014-04-18', 'Karfreitag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (47, '2014-04-21', 'Ostermontag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (48, '2014-05-01', 'Tag der Arbeit', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (49, '2014-05-29', 'Christi Himmelfahrt', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (50, '2014-06-09', 'Pfingstmontag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (51, '2014-10-03', 'Tag der Deutschen Einheit', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (52, '2014-12-25', '1. Weihnachtstag', 'BREMEN');\ninsert into holiday (id, day, name, federalstate) values (53, '2014-12-26', '2. Weihnachtstag', 'BREMEN');\n\n-- 2014 - Hamburg\ninsert into holiday (id, day, name, federalstate) values (54, '2014-01-01', 'Neujahr', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (55, '2014-04-18', 'Karfreitag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (56, '2014-04-21', 'Ostermontag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (57, '2014-05-01', 'Tag der Arbeit', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (58, '2014-05-29', 'Christi Himmelfahrt', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (59, '2014-06-09', 'Pfingstmontag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (60, '2014-10-03', 'Tag der Deutschen Einheit', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (61, '2014-12-25', '1. Weihnachtstag', 'HAMBURG');\ninsert into holiday (id, day, name, federalstate) values (62, '2014-12-26', '2. Weihnachtstag', 'HAMBURG');\n\n-- 2014 - Hessen\ninsert into holiday (id, day, name, federalstate) values (63, '2014-01-01', 'Neujahr', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (64, '2014-04-18', 'Karfreitag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (65, '2014-04-21', 'Ostermontag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (66, '2014-05-01', 'Tag der Arbeit', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (67, '2014-05-29', 'Christi Himmelfahrt', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (68, '2014-06-09', 'Pfingstmontag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (69, '2014-06-19', 'Fronleichnam', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (70, '2014-10-03', 'Tag der Deutschen Einheit', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (71, '2014-12-25', '1. Weihnachtstag', 'HESSEN');\ninsert into holiday (id, day, name, federalstate) values (72, '2014-12-26', '2. Weihnachtstag', 'HESSEN');\n\n-- 2014 - Mecklenburg-Vorpommern\ninsert into holiday (id, day, name, federalstate) values (73, '2014-01-01', 'Neujahr', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (74, '2014-04-18', 'Karfreitag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (75, '2014-04-21', 'Ostermontag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (76, '2014-05-01', 'Tag der Arbeit', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (77, '2014-05-29', 'Christi Himmelfahrt', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (78, '2014-06-09', 'Pfingstmontag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (79, '2014-10-03', 'Tag der Deutschen Einheit', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (80, '2014-10-31', 'Reformationstag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (81, '2014-12-25', '1. Weihnachtstag', 'MECKLENBURG_VORPOMMERN');\ninsert into holiday (id, day, name, federalstate) values (82, '2014-12-26', '2. Weihnachtstag', 'MECKLENBURG_VORPOMMERN');\n\n-- 2014 - Niedersachsen\ninsert into holiday (id, day, name, federalstate) values (83, '2014-01-01', 'Neujahr', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (84, '2014-04-18', 'Karfreitag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (85, '2014-04-21', 'Ostermontag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (86, '2014-05-01', 'Tag der Arbeit', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (87, '2014-05-29', 'Christi Himmelfahrt', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (88, '2014-06-09', 'Pfingstmontag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (89, '2014-10-03', 'Tag der Deutschen Einheit', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (90, '2014-12-25', '1. Weihnachtstag', 'NIEDERSACHSEN');\ninsert into holiday (id, day, name, federalstate) values (91, '2014-12-26', '2. Weihnachtstag', 'NIEDERSACHSEN');\n\n-- 2014 - Nordrhein-Westfalen\ninsert into holiday (id, day, name, federalstate) values (92,  '2014-01-01', 'Neujahr', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (93,  '2014-04-18', 'Karfreitag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (94,  '2014-04-21', 'Ostermontag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (95,  '2014-05-01', 'Tag der Arbeit', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (96,  '2014-05-29', 'Christi Himmelfahrt', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (97,  '2014-06-09', 'Pfingstmontag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (98,  '2014-06-19', 'Fronleichnam', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (99,  '2014-10-03', 'Tag der Deutschen Einheit', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (100, '2014-11-01', 'Allerheiligen', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (101, '2014-12-25', '1. Weihnachtstag', 'NORDRHEIN_WESTFALEN');\ninsert into holiday (id, day, name, federalstate) values (102, '2014-12-26', '2. Weihnachtstag', 'NORDRHEIN_WESTFALEN');\n\n-- 2014 - Rheinland-Pfalz\ninsert into holiday (id, day, name, federalstate) values (103, '2014-01-01', 'Neujahr', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (104, '2014-04-18', 'Karfreitag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (105, '2014-04-21', 'Ostermontag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (106, '2014-05-01', 'Tag der Arbeit', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (107, '2014-05-29', 'Christi Himmelfahrt', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (108, '2014-06-09', 'Pfingstmontag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (109, '2014-06-19', 'Fronleichnam', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (110, '2014-10-03', 'Tag der Deutschen Einheit', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (111, '2014-11-01', 'Allerheiligen', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (112, '2014-12-25', '1. Weihnachtstag', 'RHEINLAND_PFALZ');\ninsert into holiday (id, day, name, federalstate) values (113, '2014-12-26', '2. Weihnachtstag', 'RHEINLAND_PFALZ');\n\n-- 2014 - Saarland\ninsert into holiday (id, day, name, federalstate) values (114, '2014-01-01', 'Neujahr', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (115, '2014-04-18', 'Karfreitag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (116, '2014-04-21', 'Ostermontag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (117, '2014-05-01', 'Tag der Arbeit', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (118, '2014-05-29', 'Christi Himmelfahrt', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (119, '2014-06-09', 'Pfingstmontag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (120, '2014-06-19', 'Fronleichnam', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (121, '2014-08-15', 'Mariä Himmelfahrt', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (122, '2014-10-03', 'Tag der Deutschen Einheit', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (123, '2014-11-01', 'Allerheiligen', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (124, '2014-12-25', '1. Weihnachtstag', 'SAARLAND');\ninsert into holiday (id, day, name, federalstate) values (125, '2014-12-26', '2. Weihnachtstag', 'SAARLAND');\n\n-- 2014 - Sachsen\ninsert into holiday (id, day, name, federalstate) values (126, '2014-01-01', 'Neujahr', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (127, '2014-04-18', 'Karfreitag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (128, '2014-04-21', 'Ostermontag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (129, '2014-05-01', 'Tag der Arbeit', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (130, '2014-05-29', 'Christi Himmelfahrt', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (131, '2014-06-09', 'Pfingstmontag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (132, '2014-10-03', 'Tag der Deutschen Einheit', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (133, '2014-10-31', 'Reformationstag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (134, '2014-11-19', 'Buß- und Bettag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (135, '2014-12-25', '1. Weihnachtstag', 'SACHSEN');\ninsert into holiday (id, day, name, federalstate) values (136, '2014-12-26', '2. Weihnachtstag', 'SACHSEN');\n\n-- 2014 - Sachsen-Anhalt\ninsert into holiday (id, day, name, federalstate) values (137, '2014-01-01', 'Neujahr', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (138, '2014-01-06', 'Helige Drei Könige', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (139, '2014-04-18', 'Karfreitag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (140, '2014-04-21', 'Ostermontag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (141, '2014-05-01', 'Tag der Arbeit', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (142, '2014-05-29', 'Christi Himmelfahrt', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (143, '2014-06-09', 'Pfingstmontag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (144, '2014-10-03', 'Tag der Deutschen Einheit', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (145, '2014-10-31', 'Reformationstag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (146, '2014-12-25', '1. Weihnachtstag', 'SACHSEN_ANHALT');\ninsert into holiday (id, day, name, federalstate) values (147, '2014-12-26', '2. Weihnachtstag', 'SACHSEN_ANHALT');\n\n-- 2014 - Schleswig-Holstein\ninsert into holiday (id, day, name, federalstate) values (148, '2014-01-01', 'Neujahr', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (149, '2014-04-18', 'Karfreitag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (150, '2014-04-21', 'Ostermontag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (151, '2014-05-01', 'Tag der Arbeit', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (152, '2014-05-29', 'Christi Himmelfahrt', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (153, '2014-06-09', 'Pfingstmontag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (154, '2014-10-03', 'Tag der Deutschen Einheit', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (155, '2014-12-25', '1. Weihnachtstag', 'SCHLESWIG_HOLSTEIN');\ninsert into holiday (id, day, name, federalstate) values (156, '2014-12-26', '2. Weihnachtstag', 'SCHLESWIG_HOLSTEIN');\n\n-- 2014 - Thüringen\ninsert into holiday (id, day, name, federalstate) values (157, '2014-01-01', 'Neujahr', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (158, '2014-04-18', 'Karfreitag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (159, '2014-04-21', 'Ostermontag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (160, '2014-05-01', 'Tag der Arbeit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (161, '2014-05-29', 'Christi Himmelfahrt', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (162, '2014-06-09', 'Pfingstmontag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (163, '2014-10-03', 'Tag der Deutschen Einheit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (164, '2014-10-31', 'Tag der Deutschen Einheit', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (165, '2014-12-25', 'Reformationstag', 'THUERINGEN');\ninsert into holiday (id, day, name, federalstate) values (166, '2014-12-26', '2. Weihnachtstag', 'THUERINGEN');\n\n"
  },
  {
    "path": "src/main/resources/db/migration/V4__add_invoices.sql",
    "content": "create table Invoice (\n    id int8 not null,\n    creationDate date,\n    dueDate date,\n    identifier varchar(255),\n    invoiceState varchar(255),\n    invoiceTotal numeric(19, 2),\n    version int4,\n    debitor int8,\n    primary key (id),\n    unique (identifier)\n);\n\nalter table Invoice\n    add constraint FKD80EDB0D1D75383C\n    foreign key (debitor)\n    references Company;\n"
  },
  {
    "path": "src/main/resources/db/migration/V5__modify_vacationrequests.sql",
    "content": "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",
    "content": "alter table TravelExpenseReport\n  add column submissionDate timestamp;\n\nalter table ContactPerson\n  add column roles varchar(255);\n"
  },
  {
    "path": "src/main/resources/db/migration/V7__update_travel_expense_report_submission_date_from_travel_expenses.sql",
    "content": "UPDATE TravelExpenseReport ter\n\tSET submissionDate = (\n\t\tSELECT MAX(te.submissionDate)\n\t\tFROM TravelExpense te\n\t\tWHERE te.report_id = ter.id\n\t)\nWHERE ter.submissionDate IS NULL;\n"
  },
  {
    "path": "src/main/resources/db/migration/V8__add_sick_days.sql",
    "content": "create table SickDays (\n    id int8 not null,\n    endDate date,\n    startDate date,\n    version int4,\n    employee_id int8,\n    primary key (id)\n);\n\nalter table SickDays\n    add constraint FKF63D6D555198E9B\n    foreign key (employee_id)\n    references Employee;"
  },
  {
    "path": "src/main/resources/db/migration/V9__modify_travel_expense_report.sql",
    "content": "alter table TravelExpenseReport\n  add column approvalDate timestamp;\n\nalter table TravelExpenseReport\n  add column approver_id int8;\n\nalter table TravelExpenseReport\n  add constraint FK854DBA9248918324\n  foreign key (approver_id)\n  references Employee;"
  },
  {
    "path": "src/main/resources/i18n/trackr-de.json",
    "content": "{\n    \"AUTHORITY\": {\n        \"ROLE_ADMIN\": \"Administrator\",\n        \"ROLE_SUPERVISOR\": \"Supervisor\",\n        \"ROLE_EMPLOYEE\": \"Angestellter\",\n        \"ROLES\": \"Rollen\"\n    },\n    \"COMPANY\": {\n        \"CREATE_NEW\": \"Neue Firma anlegen\",\n        \"COMPANIES\": \"Firmen\",\n        \"COMPANY_ID\": \"Eindeutiger Bezeichner\",\n        \"NAME\": \"Name\",\n        \"COMPANY_ID_CONFLICT\": \"Bezeichner bereits vergeben.\",\n        \"TIME_FOR_PAYMENT\": \"Zahlungsziel\"\n    },\n    \"ADDRESS\": {\n        \"ADDRESS\": \"Adresse\",\n        \"STREET\": \"Straße\",\n        \"HOUSE_NUMBER\": \"Hausnummer\",\n        \"CITY\": \"Stadt\",\n        \"ZIPCODE\": \"PLZ\",\n        \"COUNTRY\": \" Land\"\n    },\n    \"CONTACTPERSON\": {\n        \"CONTACTPERSON\": \"Kontaktperson\",\n        \"CONTACTPERSONS\": \"Kontaktpersonen\",\n        \"CREATE_NEW\": \"Neue Kontaktperson\",\n        \"SALUTATION\": \" Anrede\",\n        \"FIRST_NAME\": \"Vorname\",\n        \"LAST_NAME\": \"Nachname\",\n        \"EMAIL\": \"Email\",\n        \"PHONE\": \"Telefon\",\n        \"ROLES\": \"Rollen\"\n    },\n    \"EMPLOYEE\": {\n        \"CREATE_NEW\": \"Neuen Angestellten anlegen\",\n        \"EMPLOYEES\": \"Angestellte\",\n        \"EMPLOYEE\": \"Angestellte/r\",\n        \"FIRST_NAME\": \"Vorname\",\n        \"LAST_NAME\": \"Nachname\",\n        \"TITLE\": \"Titel\",\n        \"SALARY\": \"Gehalt\",\n        \"PHONE_NUMBER\": \"Telefon\",\n        \"HOURLY_COST_RATE\": \"Stundensatz\",\n        \"ADMINISTRATE_ROLES\": \"Alle Rollen\",\n        \"JOIN_DATE\": \"Eintrittsdatum\",\n        \"LEAVE_DATE\": \"Austrittsdatum\",\n        \"FEDERAL_STATE\": \"Bundesland\",\n        \"VACATION_ENTITLEMENT\": \"Urlaubsanspruch\",\n        \"DELETED\": \"gelöscht\"\n    },\n    \"CREDENTIAL\": {\n        \"EMAIL\": \"E-Mail\",\n        \"ENABLED\": \"Aktiv\",\n        \"EMAIL_CONFLICT\": \"Email bereits in Benutzung.\"\n    },\n    \"PROJECT\": {\n        \"CREATE_NEW\": \"Neues Projekt anlegen\",\n        \"PROJECTS\": \"Projekte\",\n        \"PROJECT\": \"Projekt\",\n        \"IDENTIFIER\": \"Eindeutiger Bezeichner\",\n        \"NAME\": \"Name\",\n        \"VOLUME\": \"Volumen\",\n        \"HOURLY_RATE\": \"Stundensatz\",\n        \"DAILY_RATE\": \"Tagessatz\",\n        \"FIXED_PRICE\": \"Festpreis\",\n        \"COMPANY\": \"Firma\",\n        \"DEBITOR\": \"Debitor\",\n        \"IDENTIFIER_CONFLICT\": \"Bezeichner bereits in Verwendung\"\n    },\n    \"WORKTIME\": {\n        \"DATE\": \"Datum\",\n        \"PROJECT\": \"Projekt\",\n        \"START\": \"Startzeit\",\n        \"END\": \"Endzeit\",\n        \"COMMENT\": \"Kommentar\",\n        \"TOTAL_HOURS\": \"Stunden gesamt\"\n    },\n    \"BILLABLE_TIME\": {\n        \"DATE\": \"Datum\",\n        \"BILLABLE_HOURS\": \"Rechnungsstunden\"\n    },\n    \"VACATION_REQUEST\": {\n        \"START_DATE\": \"Start\",\n        \"END_DATE\": \"Ende\",\n        \"NUMBER_OF_DAYS\": \"Tage\",\n        \"STATUS\": \"Status\",\n        \"APPROVER\": \"Genehmigt von\",\n        \"APPROVAL_DATE\": \"Genehmigt am\",\n        \"PENDING\": \"Wartet\",\n        \"APPROVED\": \"Genehmigt\",\n        \"REJECTED\": \"Abgelehnt\",\n        \"INTERVAL\": \"Zeitraum\",\n        \"EMPLOYEE\": \"Angestellter\",\n        \"SUBMITTED\": \"Eingereicht am\",\n        \"APPROVER_SYSTEM\": \"automatisch\"\n    },\n    \"TRAVEL_EXPENSE\": {\n        \"TYPE\": \"Typ\",\n        \"TYPE_VALUES\": {\n            \"HOTEL\": \"Hotel\",\n            \"TAXI\": \"Taxi\",\n            \"FLIGHT\": \"Flug\",\n            \"TRAIN\": \"Zugfahrt\",\n            \"PARKING\": \"Parken\",\n            \"OEPNV\": \"ÖPNV\",\n            \"MILEAGE_ALLOWANCE\": \"Kilometerpauschale\",\n            \"OTHER\": \"Andere\"\n        },\n        \"FROM_DATE\": \"Von\",\n        \"TO_DATE\": \"Bis\",\n        \"VAT\": \"Mehrwertsteuer\",\n        \"COST\": \"Gesamt\",\n        \"COMMENT\": \"Kommentar\",\n        \"SUBMITTED\": \"Eingereicht am\",\n        \"PAID\": \"Bezahlt\"\n    },\n    \"TRAVEL_EXPENSE_REPORT\": {\n        \"TRAVEL_EXPENSE_REPORT\": \"Reisekostenbericht\",\n        \"TRAVEL_EXPENSE_REPORTS\": \"Reisekostenberichte\",\n        \"TOTAL\": \"Summe\",\n        \"PENDING\": \"Wartend\",\n        \"APPROVED\": \"Akzeptiert\",\n        \"REJECTED\": \"Abgelehnt\",\n        \"SUBMITTED\": \"Abgeschickt\",\n        \"ID\": \"Nummber\",\n        \"EMPLOYEE\": \"Angesteller\",\n        \"APPROVER\": \"Genehmiger\",\n        \"SUBMISSION_DATE\": \"Eingereicht am\",\n        \"APPROVAL_DATE\": \"Genehmigt am\",\n        \"COMMENTS\": \"Kommentare\",\n        \"DEBITOR\": \"Debitor\",\n        \"PROJECT\": \"Projekt\"\n    },\n    \"INVOICE\": {\n        \"INVOICE\": \"Rechnung\",\n        \"INVOICES\": \"Rechnungen\",\n        \"CREATE_NEW\": \"Neue Rechnung\",\n        \"IDENTIFIER\": \"Eindeutiger Bezeichner\",\n        \"INVOICE_TOTAL\": \"Gesamtbetrag\",\n        \"DUE_DATE\": \"Fälligkeitsdatum\",\n        \"STATE\": \"Status\",\n        \"DEBITOR\": \"Debitor\",\n        \"CREATION_DATE\": \"Ausstellungsdatum\",\n        \"OUTSTANDING\": \"Ausstehend\",\n        \"PAID\": \"Bezahlt\",\n        \"OVERDUE\": \"Überfällig\",\n        \"IDENTIFIER_CONFLICT\": \"Bezeichner schon in Nutzung.\",\n        \"INVOICE_CREATED\": \"Rechnung angelegt.\"\n    },\n    \"SICK_DAYS\": {\n        \"START_DATE\": \"Startdatum\",\n        \"END_DATE\": \"Enddate\",\n        \"TOTAL_DAYS\": \"Anzahl Tage\"\n    },\n    \"DIRECTIVES\": {\n        \"COMMENT_SECTION\": {\n            \"COMMENTS\": \"Kommentare\",\n            \"TEXT\": \"Text\"\n        }\n    },\n    \"PAGES\": {\n        \"HOME\": {\n            \"WELCOME_TEXT\": \"Willkommen bei trackr\",\n            \"BREADCRUMB\": \"Home\"\n        },\n        \"ADMINISTRATION\": {\n            \"TITLE\": \"Verwaltung\",\n            \"TEXT_COMPANIES\": \"Legen Sie neue Firmen an und editieren Sie bestehende.\",\n            \"TEXT_EMPLOYEES\": \"Verwalten Sie Angestellte in trackr.\",\n            \"TEXT_PROJECTS\": \"Verwalten Sie Projekte\"\n        },\n        \"EMPLOYEE\": {\n            \"TITLE\": \"Self Services\",\n            \"TEXT_EDIT_PROFILE\": \"Editieren Sie ihr Profil\",\n            \"TEXT_EDIT_TIMESHEET\": \"Erfassen Sie Arbeitszeiten\",\n            \"TEXT_VACATION\": \"Urlaubsanträge\",\n            \"EXPENSES\": {\n                \"TITLE\": \"Reisekosten\",\n                \"DELETE_FORBIDDEN\": \"Dieser Report darf nicht gelöscht werden.\",\n                \"REIMBURSEMENT\": \"Rückerstattung\"\n            },\n            \"TEXT_TIMESHEET_OVERVIEW\": \"Arbeitszeiten Übersicht\",\n            \"TIMESHEET_OVERVIEW\": {\n                \"GROUPED_BY_PROJECT\": \"Nach Projekt gruppiert\",\n                \"HOURS_PER_DAY\": \"Stunden pro Tag\",\n                \"TOTAL\": \"Gesamt\"\n            },\n            \"ADDRESS_BOOK\": {\n                \"TITLE\": \"Adressbuch\"\n            },\n            \"SICK_DAYS\": {\n                \"TITLE\": \"Krankheitstage\"\n            }\n        },\n        \"SUPERVISOR\": {\n            \"TITLE\": \"Supervisor\",\n            \"TEXT_BILL\": \"Rechnungszeiten erfassen\",\n            \"TEXT_BILL_CREATE\": \"Rechnung erstellen\",\n            \"BILL\": {\n                \"TITLE\": \"Rechnungszeiten erfassen\",\n                \"HOURS\": \"Stunden\",\n                \"SET_ALL\": \"Alle setzen\",\n                \"SUM\": \"Summe\",\n                \"TRANSFER_HOURS\": \"Aus Stunden übernehmen\"\n            },\n            \"VACATION\": {\n                \"TITLE\": \"Urlaubsanträge\",\n                \"REALLY_DELETE\": \"Wollen Sie diesen Urlaubsantrag wirklich entfernen?\"\n            },\n            \"BILL_CREATE\": {\n                \"TITLE\": \"Rechnung erstellen\",\n                \"HOURS\": \"Stunden\",\n                \"MAN_DAYS\": \"Manntage\",\n                \"NET_PRICE\": \"Netto\",\n                \"GROSS_PRICE\": \"Brutto\"\n            },\n            \"TRAVEL_EXPENSE_REPORTS\": {\n                \"TITLE\": \"Reisekosten\",\n                \"EMPTY_TEXT\": \"Keine Reisekostenberichte\",\n                \"JUMP_TO_REPORT\": \"zu Report wechseln\",\n                \"APPROVED_BY\": \"Genehmigt von\"\n            },\n            \"TRAVEL_EXPENSE_REPORT\": {\n                \"NOT_FOUND\": \"Reisekostenbericht #{{id}} nicht gefunden.\",\n                \"BACK_TO_LIST\": \"Zurück zur Liste.\"\n            }\n        },\n        \"REPORTR\": {\n            \"REVENUE\": {\n                \"TITLE\": \"Einnahmen\",\n                \"TURNOVER\": \"Umsatz\",\n                \"TOTAL\": \"Gesamt\"\n            },\n            \"VACATION\": {\n                \"TITLE\": \"Urlaub\",\n                \"DAYS\": \"Tage\"\n            },\n            \"PROJECT_HOURS\": {\n                \"TITLE\": \"Projektstunden\",\n                \"TRACKED_HOURS\": \"Erfasste Stunden\",\n                \"BILLED_HOURS\": \"Berechnete Stunden\"\n            },\n            \"EMPLOYEE_HOURS\": {\n                \"TITLE\": \"Arbeitsstunden\",\n                \"WORKED_HOURS\": \"Gearbeitete Stunden\"\n            },\n            \"TRAVEL_EXPENSE\": {\n                \"TITLE\": \"Reisekosten\",\n                \"EXPENSES\": \"Ausgaben\"\n            },\n            \"SICK_DAYS\": {\n                \"TITLE\": \"Krankheitstage\"\n            },\n            \"EXPENSES_DEBITOR\": {\n                \"TITLE\": \"Reisekosten nach Debitor\"\n            }\n        }\n    },\n    \"ACTIONS\": {\n        \"OK\": \"Ok\",\n        \"CONFIRM\": \"Bestätigen\",\n        \"GO\": \"Los\",\n        \"ACTIONS\": \"Aktionen\",\n        \"SAVE\": \"Speichern\",\n        \"NEW\": \"Neu\",\n        \"CANCEL\": \"Abbrechen\",\n        \"EDIT\": \"Editieren\",\n        \"CLOSE\": \"Schließen\",\n        \"CLEAR\": \"Löschen\",\n        \"RESET\": \"Zurücksetzen\",\n        \"APPROVE\": \"Genehmigen\",\n        \"REJECT\": \"Ablehnen\",\n        \"SUBMIT\": \"Abschicken\",\n        \"REMOVE\": \"Löschen\",\n        \"ADD\": \"Hinzufügen\",\n        \"BACK\": \"Zurück\",\n        \"SEARCH\": \"Suchen\",\n        \"DELETE\": \"Löschen\",\n        \"REALLY_DELETE\": \"Wirklich löschen?\",\n        \"DOWNLOAD\": \"Herunterladen\"\n    },\n    \"FIELDS\": {\n        \"OPTIONAL\": \"optional\"\n    },\n    \"DATE\": {\n        \"TODAY\": \"Heute\",\n        \"WEEKS\": \"Wochen\"\n    },\n    \"LANGUAGE\": \"Sprache\",\n    \"ERRORS\": {\n        \"FAILED_REQUEST\": \"Aufruf fehlgeschlagen.\"\n    }\n}"
  },
  {
    "path": "src/main/resources/i18n/trackr-en.json",
    "content": "{\n    \"AUTHORITY\": {\n        \"ROLE_ADMIN\": \"Administrator\",\n        \"ROLE_SUPERVISOR\": \"Supervisor\",\n        \"ROLE_EMPLOYEE\": \"Employee\",\n        \"ROLES\": \"Roles\"\n    },\n    \"COMPANY\": {\n        \"CREATE_NEW\": \"Create new company\",\n        \"COMPANIES\": \"Companies\",\n        \"COMPANY_ID\": \"Unique identifier\",\n        \"NAME\": \"Name\",\n        \"COMPANY_ID_CONFLICT\": \"Identifier already in use.\",\n        \"TIME_FOR_PAYMENT\": \"Time for payment\"\n    },\n    \"ADDRESS\": {\n        \"ADDRESS\": \"Address\",\n        \"STREET\": \"Street\",\n        \"HOUSE_NUMBER\": \"House number\",\n        \"CITY\": \"City\",\n        \"ZIPCODE\": \"Zipcode\",\n        \"COUNTRY\": \"Country\"\n    },\n    \"CONTACTPERSON\": {\n        \"CONTACTPERSON\": \"Contact person\",\n        \"CONTACTPERSONS\": \"Contact persons\",\n        \"CREATE_NEW\": \"New contact person\",\n        \"SALUTATION\": \" Salutation\",\n        \"FIRST_NAME\": \"First name\",\n        \"LAST_NAME\": \"Last name\",\n        \"EMAIL\": \"Email\",\n        \"PHONE\": \"Phone\",\n        \"ROLES\": \"Roles\"\n    },\n    \"EMPLOYEE\": {\n        \"CREATE_NEW\": \"Create new employee\",\n        \"EMPLOYEES\": \"Employees\",\n        \"EMPLOYEE\": \"Employee\",\n        \"FIRST_NAME\": \"First name\",\n        \"LAST_NAME\": \"Last name\",\n        \"TITLE\": \"Title\",\n        \"SALARY\": \"Salary\",\n        \"PHONE_NUMBER\": \"Phone number\",\n        \"HOURLY_COST_RATE\": \"Hourly cost rate\",\n        \"ADMINISTRATE_ROLES\": \"All roles\",\n        \"JOIN_DATE\": \"Join date\",\n        \"LEAVE_DATE\": \"Leave date\",\n        \"FEDERAL_STATE\": \"Federal state\",\n        \"VACATION_ENTITLEMENT\": \"Vacation entitlement\",\n        \"DELETED\": \"deleted\"\n    },\n    \"CREDENTIAL\": {\n        \"EMAIL\": \"E-Mail\",\n        \"ENABLED\": \"Enabled\",\n        \"EMAIL_CONFLICT\": \"Email already in use.\"\n    },\n    \"PROJECT\": {\n        \"CREATE_NEW\": \"Create new project\",\n        \"PROJECTS\": \"Projects\",\n        \"PROJECT\": \"Project\",\n        \"IDENTIFIER\": \"Identifier\",\n        \"NAME\": \"Name\",\n        \"VOLUME\": \"Volume\",\n        \"HOURLY_RATE\": \"Hourly rate\",\n        \"DAILY_RATE\": \"Daily rate\",\n        \"FIXED_PRICE\": \"Fixed price\",\n        \"COMPANY\": \"Company\",\n        \"DEBITOR\": \"Debitor\",\n        \"IDENTIFIER_CONFLICT\": \"Identifier in use.\"\n    },\n    \"BILLABLE_TIME\": {\n        \"DATE\": \"Date\",\n        \"BILLABLE_HOURS\": \"Billable hours\"\n    },\n    \"VACATION_REQUEST\": {\n        \"START_DATE\": \"Start date\",\n        \"END_DATE\": \"End date\",\n        \"NUMBER_OF_DAYS\": \"Number of days\",\n        \"STATUS\": \"Status\",\n        \"APPROVER\": \"Approved by\",\n        \"APPROVAL_DATE\": \"Approval date\",\n        \"PENDING\": \"Pending\",\n        \"APPROVED\": \"Approved\",\n        \"REJECTED\": \"Rejected\",\n        \"INTERVAL\": \"Interval\",\n        \"EMPLOYEE\": \"Employee\",\n        \"SUBMITTED\": \"Submitted\",\n        \"APPROVER_SYSTEM\": \"system\"\n    },\n    \"TRAVEL_EXPENSE\": {\n        \"TYPE\": \"Type\",\n        \"TYPE_VALUES\": {\n            \"HOTEL\": \"Hotel\",\n            \"TAXI\": \"Taxi\",\n            \"FLIGHT\": \"Flight\",\n            \"TRAIN\": \"Train\",\n            \"PARKING\": \"Parking\",\n            \"OEPNV\": \"ÖPNV\",\n            \"MILEAGE_ALLOWANCE\": \"Mileage allowance\",\n            \"OTHER\": \"Other\"\n        },\n        \"FROM_DATE\": \"From\",\n        \"TO_DATE\": \"To\",\n        \"VAT\": \"VAT\",\n        \"COST\": \"Total\",\n        \"COMMENT\": \"Comment\",\n        \"SUBMITTED\": \"Submitted\",\n        \"PAID\": \"Paid\"\n    },\n    \"TRAVEL_EXPENSE_REPORT\": {\n        \"TRAVEL_EXPENSE_REPORT\": \"Travel expense report\",\n        \"TRAVEL_EXPENSE_REPORTS\": \"Travel expense reports\",\n        \"TOTAL\": \"Total\",\n        \"PENDING\": \"Pending\",\n        \"APPROVED\": \"Approved\",\n        \"REJECTED\": \"Rejected\",\n        \"SUBMITTED\": \"Submitted\",\n        \"ID\": \"Id\",\n        \"EMPLOYEE\": \"Employee\",\n        \"APPROVER\": \"Approver\",\n        \"SUBMISSION_DATE\": \"Submission date\",\n        \"APPROVAL_DATE\": \"Approval date\",\n        \"COMMENTS\": \"Comments\",\n        \"DEBITOR\": \"Debitor\",\n        \"PROJECT\": \"Project\"\n    },\n    \"INVOICE\": {\n        \"INVOICE\": \"Invoice\",\n        \"INVOICES\": \"Invoices\",\n        \"CREATE_NEW\": \"New invoice\",\n        \"IDENTIFIER\": \"Identifier\",\n        \"INVOICE_TOTAL\": \"Total\",\n        \"DUE_DATE\": \"Due date\",\n        \"STATE\": \"State\",\n        \"DEBITOR\": \"Debitor\",\n        \"CREATION_DATE\": \"Creation date\",\n        \"OUTSTANDING\": \"Outstanding\",\n        \"PAID\": \"Paid\",\n        \"OVERDUE\": \"Overdue\",\n        \"IDENTIFIER_CONFLICT\": \"Identifier already in use.\",\n        \"INVOICE_CREATED\": \"Invoice created.\"\n    },\n    \"WORKTIME\": {\n        \"DATE\": \"Date\",\n        \"PROJECT\": \"Project\",\n        \"START\": \"Start time\",\n        \"END\": \"End time\",\n        \"COMMENT\": \"Comment\",\n        \"TOTAL_HOURS\": \"Total hours\"\n    },\n    \"SICK_DAYS\": {\n        \"START_DATE\": \"Start date\",\n        \"END_DATE\": \"End date\",\n        \"TOTAL_DAYS\": \"Total days\"\n    },\n    \"DIRECTIVES\": {\n        \"COMMENT_SECTION\": {\n            \"COMMENTS\": \"Comments\",\n            \"TEXT\": \"Text\"\n        }\n    },\n    \"PAGES\": {\n        \"HOME\": {\n            \"WELCOME_TEXT\": \"Welcome to trackr\",\n            \"BREADCRUMB\": \"Home\"\n        },\n        \"ADMINISTRATION\": {\n            \"TITLE\": \"Administration\",\n            \"TEXT_COMPANIES\": \"Edit and create companies.\",\n            \"TEXT_EMPLOYEES\": \"Administrate employees in trackr.\",\n            \"TEXT_PROJECTS\": \"Administrate projects\"\n        },\n        \"EMPLOYEE\": {\n            \"TITLE\": \"Self Services\",\n            \"TEXT_EDIT_PROFILE\": \"Edit your profile\",\n            \"TEXT_EDIT_TIMESHEET\": \"Track times\",\n            \"TEXT_VACATION\": \"Vacation request\",\n            \"EXPENSES\": {\n                \"TITLE\": \"Travel expenses\",\n                \"DELETE_FORBIDDEN\": \"You cannot delete this report.\",\n                \"REIMBURSEMENT\": \"Reimbursement\"\n            },\n            \"TEXT_TIMESHEET_OVERVIEW\": \"Working times overview\",\n            \"TIMESHEET_OVERVIEW\": {\n                \"GROUPED_BY_PROJECT\": \"Grouped by project\",\n                \"HOURS_PER_DAY\": \"Hours per day\",\n                \"TOTAL\": \"Total\"\n            },\n            \"ADDRESS_BOOK\": {\n                \"TITLE\": \"Address book\"\n            },\n            \"SICK_DAYS\": {\n                \"TITLE\": \"Sick days\"\n            }\n        },\n        \"SUPERVISOR\": {\n            \"TITLE\": \"Supervisor\",\n            \"TEXT_BILL\": \"Enter billable hours\",\n            \"TEXT_BILL_CREATE\": \"Create bill\",\n            \"BILL\": {\n                \"TITLE\": \"Track billable hours\",\n                \"HOURS\": \"Hours\",\n                \"SET_ALL\": \"Set all\",\n                \"SUM\": \"Sum\",\n                \"TRANSFER_HOURS\": \"Transfer from hours\"\n            },\n            \"BILL_CREATE\": {\n                \"TITLE\": \"Create bill\",\n                \"HOURS\": \"Hours\",\n                \"MAN_DAYS\": \"Man days\",\n                \"NET_PRICE\": \"Net price\",\n                \"GROSS_PRICE\": \"Gross price\"\n            },\n            \"VACATION\": {\n                \"TITLE\": \"Vacation requests\",\n                \"REALLY_DELETE\": \"Do you really want to remove the vacation request?\"\n            },\n            \"TRAVEL_EXPENSE_REPORTS\": {\n                \"TITLE\": \"Travel expenses\",\n                \"EMPTY_TEXT\": \"No submitted travel expense reports.\",\n                \"JUMP_TO_REPORT\": \"jump to report\",\n                \"APPROVED_BY\": \"Approved by\"\n            },\n            \"TRAVEL_EXPENSE_REPORT\": {\n                \"NOT_FOUND\": \"Travel expense report #{{id}} not found.\",\n                \"BACK_TO_LIST\": \"Back to list.\"\n            }\n        },\n        \"REPORTR\": {\n            \"REVENUE\": {\n                \"TITLE\": \"Revenues\",\n                \"TURNOVER\": \"Turnover\",\n                \"TOTAL\": \"Total\"\n            },\n            \"VACATION\": {\n                \"TITLE\": \"Vacation\",\n                \"DAYS\": \"Days\"\n            },\n            \"PROJECT_HOURS\": {\n                \"TITLE\": \"Project hours\",\n                \"TRACKED_HOURS\": \"Tracked hours\",\n                \"BILLED_HOURS\": \"Billed hours\"\n            },\n            \"EMPLOYEE_HOURS\": {\n                \"TITLE\": \"Employee hours\",\n                \"WORKED_HOURS\": \"Worked hours\"\n            },\n            \"TRAVEL_EXPENSE\": {\n                \"TITLE\": \"Travel expenses\",\n                \"EXPENSES\": \"Expenses\"\n            },\n            \"SICK_DAYS\": {\n                \"TITLE\": \"Sick days\"\n            },\n            \"EXPENSES_DEBITOR\": {\n                \"TITLE\": \"Expenses by debitor\"\n            }\n\n        },\n        \"BREADCRUMB_UNKNOWN\": \"unknown\"\n    },\n    \"ACTIONS\": {\n        \"OK\": \"Ok\",\n        \"CONFIRM\": \"Confirm\",\n        \"GO\": \"Go\",\n        \"ACTIONS\": \"Actions\",\n        \"SAVE\": \"Save\",\n        \"NEW\": \"New\",\n        \"CANCEL\": \"Cancel\",\n        \"EDIT\": \"Edit\",\n        \"CLOSE\": \"Close\",\n        \"CLEAR\": \"Clear\",\n        \"RESET\": \"Reset\",\n        \"APPROVE\": \"Approve\",\n        \"REJECT\": \"Reject\",\n        \"SUBMIT\": \"Submit\",\n        \"REMOVE\": \"Remove\",\n        \"ADD\": \"Add\",\n        \"BACK\": \"Back\",\n        \"SEARCH\": \"Search\",\n        \"DELETE\": \"Delete\",\n        \"REALLY_DELETE\": \"Really delete?\",\n        \"DOWNLOAD\": \"Download\"\n    },\n    \"FIELDS\": {\n        \"OPTIONAL\": \"optional\"\n    },\n    \"DATE\": {\n        \"TODAY\": \"Today\",\n        \"WEEKS\": \"Weeks\"\n    },\n    \"LANGUAGE\": \"Language\",\n    \"ERRORS\": {\n        \"FAILED_REQUEST\": \"Request failed.\"\n    }\n}"
  },
  {
    "path": "src/main/resources/i18n/validation/messages_de.properties",
    "content": "validation.date.endAfterBegin=Start darf nicht nach Ende sein\nvalidation.company.projectBelongsTo=Das Projekt muss zu der Firma gehören."
  },
  {
    "path": "src/main/resources/i18n/validation/messages_en.properties",
    "content": "validation.date.endAfterBegin=Start must not be after end.\nvalidation.company.projectBelongsTo=The project must belong to the company."
  },
  {
    "path": "src/main/resources/logback-console.xml",
    "content": "<configuration>\n\n    <property name=\"charset\" value=\"UTF-8\"/>\n    <property name=\"pattern\" value=\"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\"/>\n\n    <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n        <encoder>\n            <charset>${charset}</charset>\n            <pattern>${pattern}</pattern>\n        </encoder>\n    </appender>\n\n    <!-- show hibernate sql with debug -->\n    <logger name=\"org.hibernate.SQL\" level=\"info\"/>\n    <!-- show bound hibernate parameters with trace -->\n    <logger name=\"org.hibernate.type\" level=\"info\"/>\n\n    <logger name=\"org.springframework.web\" level=\"info\"/>\n\n    <logger name=\"org.springframework.data.rest\" level=\"info\"/>\n\n    <logger name=\"org.springframework.security\" level=\"info\"/>\n\n    <logger name=\"de.techdev\" level=\"debug\"/>\n\n    <root level=\"warn\">\n        <appender-ref ref=\"STDOUT\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "src/main/resources/logback-file.xml",
    "content": "<configuration>\n\n    <property name=\"charset\" value=\"UTF-8\"/>\n    <property name=\"pattern\" value=\"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n\"/>\n\n    <appender name=\"FILE\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n        <file>/opt/techdev/trackr-backend/logs/trackr-backend.log</file>\n        <rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n            <fileNamePattern>/opt/techdev/trackr-backend/logs/trackr-backend_%d{yyyy-MM-dd}.%i.log</fileNamePattern>\n            <timeBasedFileNamingAndTriggeringPolicy class=\"ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP\">\n                <maxFileSize>5MB</maxFileSize>\n            </timeBasedFileNamingAndTriggeringPolicy>\n            <maxHistory>30</maxHistory>\n        </rollingPolicy>\n        <encoder>\n            <charset>${charset}</charset>\n            <pattern>${pattern}</pattern>\n        </encoder>\n    </appender>\n\n    <!-- show hibernate sql with debug -->\n    <logger name=\"org.hibernate.SQL\" level=\"info\"/>\n    <!-- show bound hibernate parameters with trace -->\n    <logger name=\"org.hibernate.type\" level=\"info\"/>\n\n    <logger name=\"org.springframework.web\" level=\"info\"/>\n\n    <logger name=\"org.springframework.data.rest\" level=\"info\"/>\n\n    <logger name=\"org.springframework.security\" level=\"info\"/>\n\n    <logger name=\"de.techdev\" level=\"debug\"/>\n\n    <root level=\"warn\">\n        <appender-ref ref=\"FILE\"/>\n    </root>\n\n</configuration>"
  },
  {
    "path": "src/main/resources/pdfTemplates/travel-expenses/report.html",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n    <style>\n        html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=\"checkbox\"],input[type=\"radio\"]{box-sizing:border-box;padding:0}input[type=\"number\"]::-webkit-inner-spin-button,input[type=\"number\"]::-webkit-outer-spin-button{height:auto}input[type=\"search\"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=\"search\"]::-webkit-search-cancel-button,input[type=\"search\"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:\" (\" attr(href) \")\"}abbr[title]:after{content:\" (\" attr(title) \")\"}a[href^=\"javascript:\"]:after,a[href^=\"#\"]:after{content:\"\"}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff !important}.navbar{display:none}.table td,.table th{background-color:#fff !important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;width:100% \\9;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;width:100% \\9;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\\2014 \\00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\\00A0 \\2014'}blockquote:before,blockquote:after{content:\"\"}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=\"col-\"]{position:static;float:none;display:table-column}table td[class*=\"col-\"],table th[class*=\"col-\"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after{content:\" \";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important;visibility:hidden !important}.affix{position:fixed;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}\n    </style>\n</head>\n<body>\n<div class=\"container\">\n    <h1 class=\"page-header\"> Travel Expense Report #<span th:text=\"${report.id}\"></span></h1>\n\n    <div class=\"row\">\n        <div class=\"col-md-4\">\n            <table class=\"table\">\n                <tr>\n                    <td>Submitted by:</td>\n                    <td><b th:text=\"${report.employee.firstName} + ' ' + ${report.employee.lastName}\">Mister Techdev</b></td>\n                </tr>\n                <tr>\n                    <td>Debitor:</td>\n                    <td><span th:text=\"${report.debitor.name}\">Techdev</span></td>\n                </tr>\n                <tr th:if=\"${report.project}\">\n                    <td>Project:</td>\n                    <td><span th:text=\"${report.project.name}\">Techdev</span></td>\n                </tr>\n                <tr>\n                    <td>Period:</td>\n                    <td><span th:if=\"${startDate}\" th:text=\"${#dates.format(startDate, 'dd.MM.yyyy')}\">10.10.2013</span> -\n                        <span th:if=\"${endDate}\" th:text=\"${#dates.format(endDate, 'dd.MM.yyyy')}\">13.10.2013</span></td>\n                </tr>\n                <tr>\n                    <td>Total:</td>\n                    <td th:text=\"${totalCost} + ' €'\">500 €</td>\n                </tr>\n                <tr>\n                    <td>Reimbursement:</td>\n                    <td th:text=\"${totalReimbursement} + ' €'\">500 €</td>\n                </tr>\n            </table>\n        </div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col-md-10\">\n            <table class=\"table table-bordered\">\n                <tr>\n                    <th>Type</th>\n                    <th>From</th>\n                    <th>To</th>\n                    <th>VAT</th>\n                    <th>Total</th>\n                    <th>Paid</th>\n                    <th>Comment</th>\n                </tr>\n                <tr th:each=\"expense : ${report.expenses}\">\n                    <td th:text=\"${expense.type}\">TAXI</td>\n                    <td th:text=\"${#dates.format(expense.fromDate, 'dd.MM.yyyy')}\">10.10.2013</td>\n                    <td th:text=\"${#dates.format(expense.toDate, 'dd.MM.yyyy')}\">13.10.2013</td>\n                    <td th:text=\"${expense.vat} + '%'\">12%</td>\n                    <td th:text=\"${expense.cost} + ' €'\">34 €</td>\n                    <td>\n                        <span th:if=\"${expense.paid}\">x</span>\n                    </td>\n                    <td th:text=\"${expense.comment}\">Comment</td>\n                </tr>\n            </table>\n        </div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col-md-3\">\n            Date: <span th:text=\"${#dates.format(today, 'dd.MM.yyyy')}\">24.07.1983</span>\n        </div>\n    </div>\n    <br/><br/><br/><br/><br/>\n\n    <div class=\"row\">\n        <div class=\"col-md-offset-2 col-md-7\">\n            <span>Signature</span>\n            <div style=\"border-bottom: 1px solid black\"></div>\n        </div>\n    </div>\n\n</div>\n</body>\n</html>"
  },
  {
    "path": "src/test/java/de/techdev/test/FlywayTest.java",
    "content": "package de.techdev.test;\n\nimport org.flywaydb.core.Flyway;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;\nimport org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;\nimport org.springframework.test.context.junit4.SpringRunner;\n\nimport javax.sql.DataSource;\n\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = {FlywayTest.FlywayTestConfig.class, FlywayAutoConfiguration.FlywayConfiguration.class})\npublic class FlywayTest {\n\n    public static class FlywayTestConfig {\n\n        @Bean\n        public DataSource dataSource() {\n            return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();\n        }\n\n    }\n\n    @Autowired\n    private Flyway flyway;\n\n    @Test\n    public void migrationSucceeds() {\n        flyway.migrate();\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/InMemoryOAuth2ResourceServerConfiguration.java",
    "content": "package de.techdev.test;\n\nimport de.techdev.trackr.core.security.OAuth2ResourceServerConfiguration;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.context.annotation.Profile;\nimport org.springframework.security.oauth2.provider.token.TokenStore;\nimport org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;\n\nimport javax.sql.DataSource;\n\n/**\n * Uses the real OAuth2 resource server configuration but with an in memory token store so we can easily modifiy it in tests.\n */\n@Configuration\n@Profile(\"test-oauth\")\npublic class InMemoryOAuth2ResourceServerConfiguration extends OAuth2ResourceServerConfiguration {\n\n    @Override\n    public DataSource oauthDataSource() {\n        return null;\n    }\n\n    @Override\n    public TokenStore tokenStore() {\n        return new InMemoryTokenStore();\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/TestConstants.java",
    "content": "package de.techdev.test;\n\npublic class TestConstants {\n\n    /**\n     * Path to the SQL file that creates the uuid mapping table for {@link @org.springframework.test.context.jdbc.Sql} in tests.\n     */\n    public static final String CREATE_UUID_MAPPING_TABLE_SQL_FILE = \"/de/techdev/trackr/domain/tableUuidMapping.sql\";\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/TransactionalIntegrationTest.java",
    "content": "package de.techdev.test;\n\nimport de.techdev.trackr.Trackr;\nimport org.junit.runner.RunWith;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.test.context.transaction.TransactionConfiguration;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * A test that should rollback all transactions after finishing.\n */\n@SpringBootTest(classes = { Trackr.class })\n@RunWith(SpringRunner.class)\n@ActiveProfiles(value = {\"in-memory-database\"})\n@Transactional\n@TransactionConfiguration\npublic abstract class TransactionalIntegrationTest {\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/oauth/OAuthRequest.java",
    "content": "package de.techdev.test.oauth;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport static java.lang.annotation.ElementType.METHOD;\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\n@Retention(RUNTIME)\n@Target({ TYPE, METHOD })\npublic @interface OAuthRequest {\n\n    /**\n     * The roles for the OAuth access token\n     */\n    String[] value() default {\"ROLE_EMPLOYEE\"};\n\n    /**\n     * The username for the OAuth access token\n     */\n    String username() default \"employee@techdev.de\";\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/oauth/OAuthTestExecutionListener.java",
    "content": "package de.techdev.test.oauth;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.core.annotation.AnnotationUtils;\nimport org.springframework.security.core.Authentication;\nimport org.springframework.security.core.GrantedAuthority;\nimport org.springframework.security.core.authority.SimpleGrantedAuthority;\nimport org.springframework.security.core.userdetails.User;\nimport org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;\nimport org.springframework.security.oauth2.common.OAuth2AccessToken;\nimport org.springframework.security.oauth2.provider.OAuth2Authentication;\nimport org.springframework.security.oauth2.provider.OAuth2Request;\nimport org.springframework.security.oauth2.provider.token.TokenStore;\nimport org.springframework.test.context.TestContext;\nimport org.springframework.test.context.support.AbstractTestExecutionListener;\n\nimport javax.annotation.Nonnull;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.stream.Collectors;\n\nimport static java.util.Arrays.asList;\nimport static org.echocat.jomon.runtime.CollectionUtils.asSet;\n\n/**\n * Test execution listener that adds an OAuth token into the store before each method. The value of the token can be set with the\n * {@link OAuthRequest} annotation on each test method.\n */\n@Slf4j\npublic class OAuthTestExecutionListener extends AbstractTestExecutionListener {\n\n    public static final String OAUTH_TOKEN_VALUE = \"token\";\n    private final OAuth2AccessToken accessToken;\n    private final OAuth2Request clientAuthentication;\n\n    public OAuthTestExecutionListener() {\n        accessToken = new DefaultOAuth2AccessToken(OAUTH_TOKEN_VALUE);\n        // TODO no magic constants! These should probably come from the OAuthResourceServer Configuration!\n        clientAuthentication = new OAuth2Request(new HashMap<>(), \"trackr-page\", null, true, asSet(\"read\", \"write\"), asSet(\"techdev-services\"), null, null, null);\n    }\n\n    @Override\n    public void beforeTestMethod(TestContext testContext) throws Exception {\n        OAuthRequest annotation = AnnotationUtils.getAnnotation(testContext.getTestMethod(), OAuthRequest.class);\n\n        if (annotation == null) {\n            annotation = AnnotationUtils.getAnnotation(testContext.getTestClass(), OAuthRequest.class);\n        }\n\n        if(annotation == null) {\n            log.warn(\"No OAuthToken annotation for {} in class {}, did you forget it?\", testContext.getTestMethod().getName(), testContext.getTestClass().getName());\n        } else {\n            insertOauthTokenIntoStore(testContext, annotation);\n        }\n    }\n\n    private void insertOauthTokenIntoStore(TestContext testContext, @Nonnull OAuthRequest token) {\n        TokenStore tokenStore = testContext.getApplicationContext().getBean(TokenStore.class);\n        tokenStore.storeAccessToken(accessToken, new OAuth2Authentication(clientAuthentication, getAuthenticationFromAnnotation(token)));\n    }\n\n    private Authentication getAuthenticationFromAnnotation(OAuthRequest token) {\n        return new Authentication() {\n            @Override\n            public Collection<? extends GrantedAuthority> getAuthorities() {\n                return asList(token.value())\n                        .stream()\n                        .map(SimpleGrantedAuthority::new)\n                        .collect(Collectors.toSet());\n            }\n\n            @Override\n            public Object getCredentials() {\n                return null;\n            }\n\n            @Override\n            public Object getDetails() {\n                return null;\n            }\n\n            @Override\n            public Object getPrincipal() {\n                return new User(getName(), \"\", getAuthorities());\n            }\n\n            @Override\n            public boolean isAuthenticated() {\n                return true;\n            }\n\n            @Override\n            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {\n\n            }\n\n            @Override\n            public String getName() {\n                return token.username();\n            }\n        };\n    }\n\n    @Override\n    public void afterTestMethod(TestContext testContext) throws Exception {\n        TokenStore tokenStore = testContext.getApplicationContext().getBean(TokenStore.class);\n        tokenStore.removeAccessToken(accessToken);\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/rest/AbstractDomainResourceSecurityTest.java",
    "content": "package de.techdev.test.rest;\n\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static java.util.Arrays.asList;\n\npublic abstract class AbstractDomainResourceSecurityTest extends AbstractRestIntegrationTest {\n\n    /**\n     * An SQL file that empties all tables in the trackr database.\n     */\n    public static final String EMPTY_DATABASE_FILE = \"/de/techdev/trackr/domain/emptyDatabase.sql\";\n\n    protected abstract String getResourceName();\n\n    private HttpEntity<String> getJsonEntity(String content) {\n        MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>() {{\n            put(\"Content-Type\", asList(\"application/json; charset=utf-8\"));\n        }};\n        return new HttpEntity<>(content, headers);\n    }\n\n    protected ResponseEntity root() throws Exception {\n        return restTemplate.getForEntity(host + \"/\" + getResourceName(), String.class);\n    }\n\n    protected ResponseEntity one(Long id) throws Exception {\n        return oneUrl(\"/\" + getResourceName() + \"/\" + id);\n    }\n\n    protected ResponseEntity oneUrl(String url) throws Exception {\n        return restTemplate.getForEntity(host + url, String.class);\n    }\n\n    protected ResponseEntity create(String payload) throws Exception {\n        return restTemplate.exchange(host + \"/\" + getResourceName() + \"/\", HttpMethod.POST, getJsonEntity(payload), String.class);\n    }\n\n    protected ResponseEntity update(Long id, String payload) throws Exception {\n        return restTemplate.exchange(host + \"/\" + getResourceName() + \"/\" + id, HttpMethod.PUT, getJsonEntity(payload), String.class);\n    }\n\n    /**\n     * Perform a PUT on a link of a random resource (with header Content-Type: text/uri-list)\n     *\n     * @param linkName    The name of the link, will be appended to the URI of the resource (e.g. /company/0/contactPersons -> linkName = contactPersons).\n     * @param linkContent The content to PUT, e.g. /contactPersons/0\n     */\n    protected ResponseEntity updateLink(Long id, String linkName, String linkContent) throws Exception {\n        LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();\n        headers.put(\"Content-Type\", asList(\"text/uri-list\"));\n        HttpEntity<?> request = new HttpEntity<>(linkContent, headers);\n        return restTemplate.exchange(host + \"/\" + getResourceName() + \"/\" + id + \"/\" + linkName, HttpMethod.PUT, request, String.class);\n    }\n\n    protected ResponseEntity updateViaPatch(Long id, String patch) throws Exception {\n        return restTemplate.exchange(host + \"/\" + getResourceName() + \"/\" + id, HttpMethod.PATCH, getJsonEntity(patch), String.class);\n    }\n\n    protected ResponseEntity remove(Long id) throws Exception {\n        return removeUrl(\"/\" + getResourceName() + \"/\" + id);\n    }\n\n    protected ResponseEntity removeUrl(String url) throws Exception {\n        return restTemplate.exchange(host + url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/test/rest/AbstractJsonGenerator.java",
    "content": "package de.techdev.test.rest;\n\nimport javax.json.Json;\nimport javax.json.stream.JsonGeneratorFactory;\nimport java.util.function.Consumer;\n\n/**\n * Generate JSON from one of our entities. Just common operations.\n * @param <T> The entity class like Employee or Project.\n * @param <B> The type of the builder so we can return it in the base build methods with the correct type.\n */\npublic abstract class AbstractJsonGenerator<T, B extends AbstractJsonGenerator> {\n\n    private T object;\n\n    protected final JsonGeneratorFactory jsonGeneratorFactory;\n\n    public AbstractJsonGenerator() {\n        jsonGeneratorFactory = Json.createGeneratorFactory(null);\n    }\n\n    public B start() {\n        reset();\n        object = getNewTransientObject(500);\n        return getSelf();\n    }\n\n    /**\n     * With this function you can change the created object in any way you like with a lambda.\n     * @param function Function to change the state of the object being generated.\n     */\n    public final B apply(Consumer<T> function) {\n        function.accept(object);\n        return getSelf();\n    }\n\n    /**\n     * @return A String containing the JSON representation of the object.\n     */\n    public String build() {\n        return getJsonRepresentation(object);\n    }\n\n    /**\n     * The actual transformation to JSON.\n     */\n    protected abstract String getJsonRepresentation(T object);\n\n    /**\n     * Generate a new object with prefilled fields.\n     * @param i Is used to add a number to fields that maybe must be unique.\n     */\n    protected abstract T getNewTransientObject(int i);\n\n    /**\n     * Just a technical method to get the correct type of the builder in the base builder methods..\n     */\n    protected abstract B getSelf();\n\n    /**\n     * If a new build starts and this builder needs a reset you can do it here.\n     */\n    protected void reset() {\n        // default no-op\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/rest/AbstractRestIntegrationTest.java",
    "content": "package de.techdev.test.rest;\n\nimport de.techdev.test.InMemoryOAuth2ResourceServerConfiguration;\nimport de.techdev.test.oauth.OAuthTestExecutionListener;\nimport de.techdev.trackr.Trackr;\nimport org.junit.Before;\nimport org.junit.runner.RunWith;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.TestExecutionListeners;\nimport org.springframework.test.context.junit4.SpringRunner;\nimport org.springframework.web.client.RestTemplate;\n\nimport javax.json.Json;\nimport javax.json.stream.JsonGeneratorFactory;\n\n/**\n * Abstract test class to run tests that access the running REST API.\n */\n@RunWith(SpringRunner.class)\n@SpringBootTest(classes = {Trackr.class, InMemoryOAuth2ResourceServerConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@ActiveProfiles({\"in-memory-database\", \"test-oauth\", \"granular-security\"})\n@TestExecutionListeners(value = OAuthTestExecutionListener.class, mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)\npublic abstract class AbstractRestIntegrationTest {\n\n    @Value(\"${local.server.port}\")\n    private Integer serverPort;\n\n    protected JsonGeneratorFactory jsonGeneratorFactory;\n    protected RestTemplate restTemplate;\n    protected String host;\n\n    @Before\n    public void setUpMvcFields() throws Exception {\n        jsonGeneratorFactory = Json.createGeneratorFactory(null);\n        restTemplate = new TestRestTemplate(OAuthTestExecutionListener.OAUTH_TOKEN_VALUE);\n        host = \"http://localhost:\" + serverPort;\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/rest/DomainResourceTestMatchers.java",
    "content": "package de.techdev.test.rest;\n\nimport org.hamcrest.Description;\nimport org.hamcrest.Matcher;\nimport org.hamcrest.TypeSafeMatcher;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.ResponseEntity;\n\nimport static org.junit.Assert.assertEquals;\n\npublic class DomainResourceTestMatchers {\n\n    private DomainResourceTestMatchers() {\n    }\n\n    /**\n     * Functional interface for a consumer that can throw an exception.\n     * @param <T> The type to consume.\n     */\n    @FunctionalInterface\n    private static interface ConsumerWithException<T> {\n        public void accept(T item) throws Exception;\n    }\n\n    private static class ResultActionsMatcher extends TypeSafeMatcher<ResponseEntity> {\n        private String description;\n        private ConsumerWithException<ResponseEntity> test;\n\n        protected ResultActionsMatcher(String description, ConsumerWithException<ResponseEntity> test) {\n            this.description = description;\n            this.test = test;\n        }\n\n        @Override\n        protected boolean matchesSafely(ResponseEntity item) {\n            try {\n                test.accept(item);\n                return true;\n            } catch (Exception e) {\n                return false;\n            }\n        }\n\n        @Override\n        public void describeTo(Description description) {\n            description.appendText(this.description);\n        }\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 200.\n     */\n    public static Matcher<? super ResponseEntity> isAccessible() {\n        return new ResultActionsMatcher(\"accessible\", response -> assertEquals(HttpStatus.OK, response.getStatusCode()));\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 201 and the \"id\" field in the returned JSON is not null.\n     */\n    public static Matcher<? super ResponseEntity> isCreated() {\n        return new ResultActionsMatcher(\"created\", response -> assertEquals(HttpStatus.CREATED, response.getStatusCode()));\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 403.\n     */\n    public static Matcher<? super ResponseEntity> isForbidden() {\n        return new ResultActionsMatcher(\"forbidden\", response -> assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()));\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 200 and the \"id\" field in the returned JSON is not null.\n     */\n    public static Matcher<? super ResponseEntity> isUpdated() {\n        return new ResultActionsMatcher(\"updated\", response -> assertEquals(HttpStatus.OK, response.getStatusCode()));\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 204.\n     */\n    public static Matcher<? super ResponseEntity> isNoContent() {\n        return new ResultActionsMatcher(\"no content\", request -> assertEquals(HttpStatus.NO_CONTENT, request.getStatusCode()));\n    }\n\n    /**\n     * @return Matcher that checks if the HTTP status is 405.\n     */\n    public static Matcher<? super ResponseEntity> isMethodNotAllowed() {\n        return new ResultActionsMatcher(\"method not allowed\", response -> assertEquals(HttpStatus.METHOD_NOT_ALLOWED, response.getStatusCode()));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/test/rest/TestRestTemplate.java",
    "content": "package de.techdev.test.rest;\n\nimport org.apache.http.client.config.CookieSpecs;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.config.RequestConfig.Builder;\nimport org.apache.http.client.protocol.HttpClientContext;\nimport org.apache.http.protocol.HttpContext;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.HttpRequest;\nimport org.springframework.http.client.*;\nimport org.springframework.util.ClassUtils;\nimport org.springframework.web.client.DefaultResponseErrorHandler;\nimport org.springframework.web.client.RestTemplate;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.util.*;\n\n/**\n * Convenient subclass of {@link org.springframework.web.client.RestTemplate} that is suitable for integration tests.\n * They are fault tolerant, and optionally can carry OAuth2 authentication headers. If\n * Apache Http Client 4.3.2 or better is available (recommended) it will be used as the\n * client, and by default configured to ignore cookies and redirects.\n *\n * @author Moritz Schulze\n * @author Dave Syer\n * @author Phillip Webb\n */\npublic class TestRestTemplate extends RestTemplate {\n\n    /**\n     * Create a new {@link TestRestTemplate} instance with the specified credentials.\n     * @param token the token to use (or {@code null})\n     * @param httpClientOptions client options to use if the Apache HTTP Client is used\n     */\n    public TestRestTemplate(String token, HttpClientOption... httpClientOptions) {\n        if (ClassUtils.isPresent(\"org.apache.http.client.config.RequestConfig\", null)) {\n            setRequestFactory(new CustomHttpComponentsClientHttpRequestFactory(\n                    httpClientOptions));\n        }\n        addAuthentication(token);\n        setErrorHandler(new DefaultResponseErrorHandler() {\n            @Override\n            public void handleError(ClientHttpResponse response) throws IOException {\n            }\n        });\n\n    }\n\n    private void addAuthentication(String token) {\n        if (token == null) {\n            return;\n        }\n        List<ClientHttpRequestInterceptor> interceptors = Collections\n                .<ClientHttpRequestInterceptor> singletonList(new BearerAuthorizationInterceptor(\n                        token));\n        setRequestFactory(new InterceptingClientHttpRequestFactory(getRequestFactory(),\n                interceptors));\n    }\n\n    /**\n     * Options used to customize the Apache Http Client if it is used.\n     */\n    public static enum HttpClientOption {\n\n        /**\n         * Enable cookies.\n         */\n        ENABLE_COOKIES,\n\n        /**\n         * Enable redirects.\n         */\n        ENABLE_REDIRECTS\n\n    }\n\n    private static class BearerAuthorizationInterceptor implements\n            ClientHttpRequestInterceptor {\n\n        private final String token;\n\n        public BearerAuthorizationInterceptor(String token) {\n            this.token = token;\n        }\n\n        @Override\n        public ClientHttpResponse intercept(HttpRequest request, byte[] body,\n                                            ClientHttpRequestExecution execution) throws IOException {\n            request.getHeaders().add(\"Authorization\", \"Bearer \" + this.token);\n            return execution.execute(request, body);\n        }\n\n    }\n\n    protected static class CustomHttpComponentsClientHttpRequestFactory extends\n            HttpComponentsClientHttpRequestFactory {\n\n        private final String cookieSpec;\n\n        private final boolean enableRedirects;\n\n        public CustomHttpComponentsClientHttpRequestFactory(\n                HttpClientOption[] httpClientOptions) {\n            Set<HttpClientOption> options = new HashSet<>(\n                    Arrays.asList(httpClientOptions));\n            this.cookieSpec = (options.contains(HttpClientOption.ENABLE_COOKIES) ? CookieSpecs.STANDARD\n                    : CookieSpecs.IGNORE_COOKIES);\n            this.enableRedirects = options.contains(HttpClientOption.ENABLE_REDIRECTS);\n        }\n\n        @Override\n        protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {\n            HttpClientContext context = HttpClientContext.create();\n            context.setRequestConfig(getRequestConfig());\n            return context;\n        }\n\n        protected RequestConfig getRequestConfig() {\n            Builder builder = RequestConfig.custom().setCookieSpec(this.cookieSpec)\n                                           .setAuthenticationEnabled(false)\n                                           .setRedirectsEnabled(this.enableRedirects);\n            return builder.build();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/core/web/converters/DateConverterTest.java",
    "content": "package de.techdev.trackr.core.web.converters;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport static org.echocat.jomon.testing.BaseMatchers.isNull;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n/**\n * @author Moritz Schulze\n */\npublic class DateConverterTest {\n\n    private DateConverter dateConverter;\n\n    @Before\n    public void setUp() throws Exception {\n        dateConverter = new DateConverter();\n    }\n\n    @Test\n    public void convert10() throws Exception {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        Date expected = sdf.parse(\"2014-01-01\");\n        Date date = dateConverter.convert(\"2014-01-01\");\n        assertThat(date, is(expected));\n    }\n\n    @Test\n    public void convert19() throws Exception {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        Date expected = sdf.parse(\"2014-01-01 13:00:00\");\n        Date date = dateConverter.convert(\"2014-01-01 13:00:00\");\n        assertThat(date, is(expected));\n    }\n\n    @Test\n    public void convertNull() throws Exception {\n        Date date = dateConverter.convert(null);\n        assertThat(date, isNull());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void convertWrongLength() throws Exception {\n        dateConverter.convert(\"2014-01\");\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/common/FederalStateControllerIntegrationTest.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static org.junit.Assert.assertThat;\n\n@OAuthRequest\npublic class FederalStateControllerIntegrationTest extends AbstractRestIntegrationTest {\n\n    @Test\n    public void getAllFederalStates() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/federalStates\", String.class);\n        assertThat(response, isAccessible());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/common/UuidMapperIntegrationTest.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport de.techdev.test.TestConstants;\nimport de.techdev.test.TransactionalIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ActiveProfiles;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport java.util.UUID;\n\nimport static org.echocat.jomon.testing.BaseMatchers.isNotNull;\nimport static org.echocat.jomon.testing.BaseMatchers.isNull;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(TestConstants.CREATE_UUID_MAPPING_TABLE_SQL_FILE)\npublic class UuidMapperIntegrationTest extends TransactionalIntegrationTest {\n\n    @Autowired\n    private UuidMapper uuidMapper;\n\n    @Test\n    public void insertUuid() throws Exception {\n        UUID uuid = uuidMapper.createUUID(1L);\n        assertThat(uuid, isNotNull());\n    }\n\n    @Test\n    public void findUuid() throws Exception {\n        UUID uuid = uuidMapper.createUUID(1L);\n        Long id = uuidMapper.getIdFromUUID(uuid.toString());\n        assertThat(id, is(1L));\n    }\n\n    @Test\n    public void deleteUuidByUuid() throws Exception {\n        UUID uuid = uuidMapper.createUUID(1L);\n        uuidMapper.deleteUUID(uuid.toString());\n        Long id = uuidMapper.getIdFromUUID(uuid.toString());\n        assertThat(id, isNull());\n    }\n\n    @Test\n    public void deleteById() throws Exception {\n        UUID uuid = uuidMapper.createUUID(1L);\n        uuidMapper.deleteUUID(1L);\n        Long id = uuidMapper.getIdFromUUID(uuid.toString());\n        assertThat(id, isNull());\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/common/UuidMapperTest.java",
    "content": "package de.techdev.trackr.domain.common;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.*;\n\npublic class UuidMapperTest {\n\n    private UuidMapper uuidMapper;\n\n    @Before\n    public void setUp() throws Exception {\n        uuidMapper = new UuidMapper();\n    }\n\n    @Test\n    public void extractUuid() throws Exception {\n        String uuid = uuidMapper.extractUUIDFromString(\"7f08028d-700e-47b4-bec0-b82192d0f1c0\");\n        assertThat(uuid, is(\"7f08028d-700e-47b4-bec0-b82192d0f1c0\"));\n    }\n\n    @Test\n    public void extractUuidWithPrefix() throws Exception {\n        String uuid = uuidMapper.extractUUIDFromString(\"TEST 7f08028d-700e-47b4-bec0-b82192d0f1c0\");\n        assertThat(uuid, is(\"7f08028d-700e-47b4-bec0-b82192d0f1c0\"));\n    }\n\n    @Test\n    public void extractUuidWithPrefixAndSuffix() throws Exception {\n        String uuid = uuidMapper.extractUUIDFromString(\"TEST 7f08028d-700e-47b4-bec0-b82192d0f1c0 TEST2\");\n        assertThat(uuid, is(\"7f08028d-700e-47b4-bec0-b82192d0f1c0\"));\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/AddressJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\n\npublic class AddressJsonGenerator extends AbstractJsonGenerator<Address, AddressJsonGenerator> {\n\n    @Override\n    protected String getJsonRepresentation(Address address) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"version\", address.getVersion())\n          .write(\"street\", address.getStreet())\n          .write(\"houseNumber\", address.getHouseNumber())\n          .write(\"zipCode\", address.getZipCode())\n          .write(\"city\", address.getCity())\n          .write(\"country\", address.getCountry());\n\n        if (address.getId() != null) {\n            jg.write(\"id\", address.getId());\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected Address getNewTransientObject(int i) {\n        Address address = new Address();\n        address.setVersion(0);\n        address.setCity(\"city_\" + i);\n        address.setCountry(\"country_\" + i);\n        address.setHouseNumber(Integer.toString(i));\n        address.setStreet(\"street_\" + i);\n        address.setZipCode(\"zip_\" + i);\n\n        return address;\n    }\n\n    @Override\n    protected AddressJsonGenerator getSelf() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/AddressResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"address/resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_ADMIN\")\npublic class AddressResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private AddressJsonGenerator jsonGenerator = new AddressJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"addresses\";\n    }\n\n    @Test\n    @OAuthRequest\n    public void findAllNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    @OAuthRequest\n    public void one() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void createAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void putAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().apply(c -> c.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    public void patchAllowedForAdmin() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"street\\\": \\\"test\\\"}\"), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void createNotAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void putForbiddenForSupervisor() throws Exception {\n        String json = jsonGenerator.start().apply(c -> c.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void patchForbiddenForSupervisor() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"street\\\": \\\"test\\\"}\"), isForbidden());\n    }\n\n    @Test\n    public void deleteNotExported() throws Exception {\n        assertThat(remove(0L), isMethodNotAllowed());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/CompanyJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\n\npublic class CompanyJsonGenerator extends AbstractJsonGenerator<Company, CompanyJsonGenerator> {\n\n    private Long addressId;\n\n    public CompanyJsonGenerator withAddressId(Long addressId) {\n        this.addressId = addressId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(Company object) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"name\", object.getName())\n          .write(\"version\", object.getVersion())\n          .write(\"companyId\", object.getCompanyId());\n\n        if (addressId != null) {\n            jg.write(\"address\", \"/api/addresses/\" + addressId);\n        }\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        if (object.getTimeForPayment() != null) {\n            jg.write(\"timeForPayment\", object.getTimeForPayment());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected Company getNewTransientObject(int i) {\n        Company company = new Company();\n        company.setVersion(0);\n        company.setName(\"name_\" + i);\n        company.setCompanyId((long) i);\n        company.setTimeForPayment(i);\n        return company;\n    }\n\n    @Override\n    protected CompanyJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        addressId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/CompanyRepositoryTest.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.jdbc.Sql;\n\n@Sql(\"repositoryTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\npublic class CompanyRepositoryTest extends TransactionalIntegrationTest {\n\n    @Autowired\n    private CompanyRepository companyRepository;\n\n    @Test\n    public void deleteWithContactPersons() throws Exception {\n        companyRepository.delete(0L);\n    }\n\n    @Test\n    public void deleteWithProject() throws Exception {\n        companyRepository.delete(1L);\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/CompanyResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_ADMIN\")\npublic class CompanyResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private CompanyJsonGenerator jsonGenerator = new CompanyJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"companies\";\n    }\n\n    @Test\n    @OAuthRequest\n    public void rootAccessible() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest\n    public void one() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest\n    public void findByNameLikeOrderByNameAsc() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/companies/search/findByNameLikeIgnoreCaseOrderByNameAsc?name=%webshop%\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest\n    public void findByCompanyId() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/companies/search/findByCompanyId?companyId=1000\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    public void postAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().withAddressId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void putAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().apply(c -> c.setId(0L)).withAddressId(0L).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    public void patchAllowedForAdmin() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"name\\\": \\\"test\\\"}\"), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void postForbiddenForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withAddressId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void putForbiddenForSupervisor() throws Exception {\n        String json = jsonGenerator.start().apply(c -> c.setId(0L)).withAddressId(0L).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void patchForbiddenForSupervisor() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"name\\\": \\\"test\\\"}\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void addContactPersonSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"contactPersons\", \"/contactPersons/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest\n    public void addContactForbiddenForEmployee() throws Exception {\n        assertThat(updateLink(0L, \"contactPersons\", \"/contactPersons/0\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteContactAllowedForSupervisor() throws Exception {\n        assertThat(removeUrl(\"/companies/0/contactPersons/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest\n    public void deleteContactNotAllowedForEmployee() throws Exception {\n        assertThat(removeUrl(\"/companies/0/contactPersons/0\"), isForbidden());\n    }\n\n    @Test\n    public void deleteAllowedForAdmin() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteForbiddenForSupervisor() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest\n    @Ignore(\"See DATAREST-476\")\n    public void getAddress() throws Exception {\n        assertThat(oneUrl(\"/companies/0/address\"), isAccessible());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/ContactPersonJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\n\npublic class ContactPersonJsonGenerator extends AbstractJsonGenerator<ContactPerson, ContactPersonJsonGenerator> {\n\n    private Long companyId;\n\n    public ContactPersonJsonGenerator withCompanyId(Long companyId) {\n        this.companyId = companyId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(ContactPerson person) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"version\", person.getVersion())\n          .write(\"email\", person.getEmail())\n          .write(\"firstName\", person.getFirstName())\n          .write(\"lastName\", person.getLastName())\n          .write(\"phone\", person.getPhone())\n          .write(\"salutation\", person.getSalutation())\n          .write(\"roles\", person.getRoles());\n\n        if (person.getId() != null) {\n            jg.write(\"id\", person.getId());\n        }\n\n        if (companyId != null) {\n            jg.write(\"company\", \"/api/companies/\" + companyId);\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected ContactPerson getNewTransientObject(int i) {\n        ContactPerson person = new ContactPerson();\n        person.setVersion(0);\n        person.setEmail(\"person@techdev.de_\" + i);\n        person.setFirstName(\"first_name_\" + i);\n        person.setLastName(\"last_name_\" + i);\n        person.setPhone(\"phone_\" + i);\n        person.setSalutation(\"salutation_\" + i);\n        person.setRoles(\"roles_\" + i);\n\n        return person;\n    }\n\n    @Override\n    protected ContactPersonJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        companyId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/company/ContactPersonResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.company;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\nimport org.springframework.util.LinkedMultiValueMap;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"contactPerson/resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_SUPERVISOR\")\npublic class ContactPersonResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private ContactPersonJsonGenerator jsonGenerator = new ContactPersonJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"contactPersons\";\n    }\n\n    @Test\n    @OAuthRequest\n    public void rootAccessible() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest\n    public void one() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void postAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withCompanyId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void putAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withCompanyId(0L).apply(c -> c.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest\n    public void putNotAllowedForEmployee() throws Exception {\n        String json = jsonGenerator.start().withCompanyId(0L).apply(c -> c.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    public void patchAllowedForSupervisor() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"firstName\\\": \\\"Test\\\"}\"), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest\n    public void patchNotAllowedForEmployee() throws Exception {\n        assertThat(updateViaPatch(0L, \"{\\\"firstName\\\": \\\"Test\\\"}\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest\n    public void postNotAllowedForEmployee() throws Exception {\n        String json = jsonGenerator.start().withCompanyId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n//    @Test\n//    public void constraintViolation() throws Exception {\n//        mockMvc.perform(\n//                post(\"/contactPersons\")\n//                        .session(supervisorSession())\n//                        .content(\"{}\"))\n//               .andExpect(status().isBadRequest());\n//    }\n\n    @Test\n    public void deleteAllowedForSupervisor() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest\n    public void deleteForbiddenForEmployee() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_EMPLOYEE\")\n    public void updateCompanyForbiddenForEmployee() throws Exception {\n        LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();\n        headers.put(\"Content-Type\", asList(\"text/uri-list\"));\n        HttpEntity<String> requestEntity = new HttpEntity<>(\"/companies/0\", headers);\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/contactPersons/0/company\", HttpMethod.PUT, requestEntity, String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    public void updateCompanyAllowedForSupervisor() throws Exception {\n        LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();\n        headers.put(\"Content-Type\", asList(\"text/uri-list\"));\n        HttpEntity<String> requestEntity = new HttpEntity<>(\"/companies/0\", headers);\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/contactPersons/0/company\", HttpMethod.PUT, requestEntity, String.class);\n        assertThat(response, isNoContent());\n    }\n\n    @Test\n    public void deleteCompanyForbiddenForSupervisor() throws Exception {\n        assertThat(removeUrl(\"/contactPersons/0/company\"), isForbidden());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport de.techdev.trackr.domain.company.Address;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isForbidden;\nimport static java.util.Collections.singletonList;\nimport static org.junit.Assert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class EmployeeControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    private SelfEmployee selfEmployee;\n\n    @Before\n    public void setUp() throws Exception {\n        selfEmployee = new SelfEmployee();\n        selfEmployee.setFirstName(\"Foo\");\n        selfEmployee.setLastName(\"Bar\");\n        selfEmployee.setId(0L);\n        selfEmployee.setVersion(0);\n        selfEmployee.setSalary(BigDecimal.TEN);\n        selfEmployee.setTitle(\"title\");\n    }\n\n    @Test\n    public void updateSelfViaPut() throws Exception {\n        MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>() {{\n            put(\"Content-Type\", singletonList(\"application/json; charset=utf-8\"));\n        }};\n        HttpEntity<String> request = new HttpEntity<>(generateEmployeeJson(selfEmployee), headers);\n\n        ResponseEntity<String> response = restTemplate\n                .exchange(host + \"/employees/0/self\", HttpMethod.PUT, request, String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void updateOtherViaPutIsForbidden() throws Exception {\n        MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>() {{\n            put(\"Content-Type\", singletonList(\"application/json; charset=utf-8\"));\n        }};\n        HttpEntity<String> request = new HttpEntity<>(generateEmployeeJson(selfEmployee), headers);\n\n        ResponseEntity<String> response = restTemplate\n                .exchange(host + \"/employees/0/self\", HttpMethod.PUT, request, String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    public void accessSelf() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/employees/0/self\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    protected String generateEmployeeJson(SelfEmployee selfEmployee) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"firstName\", selfEmployee.getFirstName())\n          .write(\"lastName\", selfEmployee.getLastName())\n          .write(\"id\", selfEmployee.getId())\n          .write(\"version\", selfEmployee.getVersion())\n          .write(\"salary\", selfEmployee.getSalary())\n          .write(\"title\", selfEmployee.getTitle());\n\n        if (selfEmployee.getPhoneNumber() != null) {\n            jg.write(\"phoneNumber\", selfEmployee.getPhoneNumber());\n        }\n\n        Address address = selfEmployee.getAddress();\n        if (address != null) {\n            jg.writeStartObject(\"address\")\n                .write(\"id\", address.getId())\n                .write(\"version\", address.getVersion())\n                .write(\"street\", address.getStreet())\n                .write(\"houseNumber\", address.getHouseNumber())\n                .write(\"zipCode\", address.getZipCode())\n                .write(\"city\", address.getCity())\n                .write(\"country\", address.getCountry())\n            .writeEnd();\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.util.LocalDateUtil;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\n\npublic class EmployeeJsonGenerator extends AbstractJsonGenerator<Employee, EmployeeJsonGenerator> {\n\n    @Override\n    protected String getJsonRepresentation(Employee employee) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n                .write(\"firstName\", employee.getFirstName())\n                .write(\"lastName\", employee.getLastName())\n                .write(\"hourlyCostRate\", employee.getHourlyCostRate())\n                .write(\"salary\", employee.getSalary())\n                .write(\"email\", employee.getEmail())\n                .write(\"title\", employee.getTitle())\n                .write(\"federalState\", employee.getFederalState().getName());\n\n        if(employee.getVacationEntitlement() != null) {\n            jg.write(\"vacationEntitlement\", employee.getVacationEntitlement());\n        }\n\n        if (employee.getJoinDate() != null) {\n            jg.write(\"joinDate\", sdf.format(employee.getJoinDate()));\n        }\n\n        if (employee.getLeaveDate() != null) {\n            jg.write(\"leaveDate\", sdf.format(employee.getLeaveDate()));\n        }\n\n        if (employee.getPhoneNumber() != null) {\n            jg.write(\"phoneNumber\", employee.getPhoneNumber());\n        }\n\n        if (employee.getId() != null) {\n            jg.write(\"id\", employee.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected Employee getNewTransientObject(int i) {\n        Employee employee = new Employee();\n        employee.setFirstName(\"firstName_\" + i);\n        employee.setLastName(\"lastName_\" + i);\n        employee.setTitle(\"title_\" + i);\n        employee.setPhoneNumber(\"phoneNumber_\" + i);\n        employee.setSalary(BigDecimal.TEN);\n        employee.setVacationEntitlement(30f);\n        employee.setEmail(\"email\" + i + \"@techdev.de\");\n        employee.setHourlyCostRate(new BigDecimal(\"85.5\"));\n        employee.setJoinDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n        employee.setFederalState(FederalState.BERLIN);\n        return employee;\n    }\n\n    @Override\n    protected EmployeeJsonGenerator getSelf() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceIntegrationTest.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.test.context.jdbc.Sql;\nimport org.springframework.util.LinkedMultiValueMap;\nimport org.springframework.util.MultiValueMap;\n\nimport static java.util.Collections.singletonList;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.notNullValue;\nimport static org.junit.Assert.assertThat;\n\n@Sql(scripts = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\npublic class EmployeeResourceIntegrationTest extends AbstractRestIntegrationTest {\n\n    private EmployeeJsonGenerator jsonGenerator = new EmployeeJsonGenerator();\n\n    @Autowired\n    private SettingsRepository settingsRepository;\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void creatingAnEmployeeViaRestAlsoCreatesInitialLocaleSettings() throws Exception {\n        MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>() {{\n            put(\"Content-Type\", singletonList(\"application/json; charset=utf-8\"));\n        }};\n\n        Employee employee = jsonGenerator.getNewTransientObject(500);\n        employee.setEmail(\"email@techdev.de\");\n        HttpEntity<String> request = new HttpEntity<>(jsonGenerator.getJsonRepresentation(employee), headers);\n        restTemplate.exchange(host + \"/employees\", HttpMethod.POST, request, String.class);\n\n        Settings settings = settingsRepository.findByTypeAndEmployee_Email(Settings.SettingsType.LOCALE, \"email@techdev.de\");\n        assertThat(settings, is(notNullValue()));\n        assertThat(settings.getValue(), is(\"de\"));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/EmployeeResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_SUPERVISOR\")\npublic class EmployeeResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    @Override\n    protected String getResourceName() {\n        return \"employees\";\n    }\n\n    @Test\n    @OAuthRequest\n    public void rootNotAllowedForEmployees() throws Exception {\n        assertThat(root(), isForbidden());\n    }\n\n    @Test\n    public void rootAllowedForSupervisors() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    public void oneIsAllowedForSupervisor() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"employee@techdev.de\")\n    public void oneIsAllowedForSelf() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void oneIsForbiddenForOtherEmployee() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n//    @Test\n//    public void postAllowedForAdmins() throws Exception {\n//        assertThat(create(adminSession()), isCreated());\n//    }\n\n//    @Test\n//    public void putAllowedForSupervisors() throws Exception {\n//        assertThat(update(supervisorSession()), isUpdated());\n//    }\n\n//    @Test\n//    public void patchAllowedForSupervisors() throws Exception {\n//        assertThat(updateViaPatch(supervisorSession(), \"{\\\"firstName\\\": \\\"Test\\\"}\"), isUpdated());\n//    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void deleteAllowedForAdmins() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n//    @Test\n//    public void postForbiddenForSupervisor() throws Exception {\n//        assertThat(create(supervisorSession()), isForbidden());\n//    }\n\n//    @Test\n//    public void putForbiddenForEmployee() throws Exception {\n//        assertThat(update(employee -> employeeSession(employee.getEmail())), isForbidden());\n//    }\n\n    @Test\n    public void deleteForbiddenForSupervisor() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    protected String getJsonRepresentation(Employee employee) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n          .write(\"firstName\", employee.getFirstName())\n          .write(\"lastName\", employee.getLastName())\n          .write(\"hourlyCostRate\", employee.getHourlyCostRate())\n          .write(\"salary\", employee.getSalary())\n          .write(\"email\", employee.getEmail())\n          .write(\"title\", employee.getTitle())\n          .write(\"federalState\", employee.getFederalState().getName());\n\n        if(employee.getVacationEntitlement() != null) {\n            jg.write(\"vacationEntitlement\", employee.getVacationEntitlement());\n        }\n\n        if (employee.getJoinDate() != null) {\n            jg.write(\"joinDate\", sdf.format(employee.getJoinDate()));\n        }\n\n        if (employee.getLeaveDate() != null) {\n            jg.write(\"leaveDate\", sdf.format(employee.getLeaveDate()));\n        }\n\n        if (employee.getPhoneNumber() != null) {\n            jg.write(\"phoneNumber\", employee.getPhoneNumber());\n        }\n\n        if (employee.getId() != null) {\n            jg.write(\"id\", employee.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/SelfEmployeeRepositoryTest.java",
    "content": "package de.techdev.trackr.domain.employee;\n\nimport de.techdev.trackr.domain.company.Address;\nimport de.techdev.trackr.domain.company.AddressRepository;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\n\nimport java.math.BigDecimal;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.eq;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class SelfEmployeeRepositoryTest {\n\n    @InjectMocks\n    private SelfEmployeeRepository selfEmployeeRepository;\n\n    @Mock\n    private EmployeeRepository employeeRepository;\n\n    @Mock\n    private AddressRepository addressRepository;\n\n    @Before\n    public void setUp() throws Exception {\n        Employee employee = new Employee();\n        employee.setId(0L);\n        employee.setTitle(\"oldTitle\");\n        employee.setSalary(BigDecimal.ONE);\n        when(employeeRepository.findOne(eq(0L))).thenReturn(employee);\n        when(employeeRepository.save(any(Employee.class))).thenAnswer(inv -> inv.getArguments()[0]);\n        when(addressRepository.save(any(Address.class))).thenAnswer(inv -> inv.getArguments()[0]);\n    }\n\n    @Test\n    public void updateSelfUpdatesAllAllowedFields() throws Exception {\n        SelfEmployee selfEmployee = new SelfEmployee();\n        selfEmployee.setId(0l);\n        selfEmployee.setFirstName(\"firstName\");\n        selfEmployee.setLastName(\"lastName\");\n        selfEmployee.setPhoneNumber(\"12345\");\n\n        Employee updatedEmployee = selfEmployeeRepository.save(0L, selfEmployee);\n        assertThat(updatedEmployee.getId(), is(0l));\n        assertThat(updatedEmployee.getFirstName(), is(\"firstName\"));\n        assertThat(updatedEmployee.getLastName(), is(\"lastName\"));\n        assertThat(updatedEmployee.getPhoneNumber(), is(\"12345\"));\n    }\n\n    @Test\n    public void updateSelfDoesNotUpdateForbiddenFields() throws Exception {\n        SelfEmployee selfEmployee = new SelfEmployee();\n        selfEmployee.setId(0l);\n        selfEmployee.setSalary(BigDecimal.TEN);\n        selfEmployee.setTitle(\"title\");\n\n        Employee updatedEmployee = selfEmployeeRepository.save(0L, selfEmployee);\n        assertThat(updatedEmployee.getTitle(), is(\"oldTitle\"));\n        assertThat(updatedEmployee.getSalary(), is(BigDecimal.ONE));\n    }\n\n    @Test\n    public void updateSelfUpdatesTheAddressWhenItIsNotNull() throws Exception {\n        SelfEmployee selfEmployee = new SelfEmployee();\n        Address address = new Address();\n        selfEmployee.setAddress(address);\n\n        Employee updatedEmployee = selfEmployeeRepository.save(0L, selfEmployee);\n\n        verify(addressRepository).save(eq(address));\n        assertThat(updatedEmployee.getAddress(), is(address));\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static org.junit.Assert.assertThat;\n\n@OAuthRequest\npublic class AddressBookControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    @Test\n    public void rootIsAccessible() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/address_book\", String.class);\n        assertThat(response, isAccessible());\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/addressbook/AddressBookControllerTest.java",
    "content": "package de.techdev.trackr.domain.employee.addressbook;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.util.List;\n\nimport static java.util.Collections.singletonList;\nimport static org.echocat.jomon.testing.BaseMatchers.isNotEmpty;\nimport static org.junit.Assert.assertThat;\n\npublic class AddressBookControllerTest {\n\n    private AddressBookController addressBookController;\n\n    @Before\n    public void setUp() throws Exception {\n        addressBookController = new AddressBookController();\n    }\n\n    @Test\n    public void transformEmployees() throws Exception {\n        Employee employee = new Employee();\n        List<Employee> listOfEmployees = singletonList(employee);\n        List<EmployeeForAddressBookDTO> employeeForAddressBookDTOs = addressBookController.transformToReducedEmployees(listOfEmployees);\n        assertThat(employeeForAddressBookDTOs, isNotEmpty());\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class TravelExpenseJsonGenerator extends AbstractJsonGenerator<TravelExpense, TravelExpenseJsonGenerator> {\n\n    private Long reportId;\n\n    public TravelExpenseJsonGenerator withReportId(Long reportId) {\n        this.reportId = reportId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(TravelExpense object) {\n        if (reportId == null) {\n            throw new IllegalStateException(\"Report id must not be null\");\n        }\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        SimpleDateFormat sdf2 = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss\");\n        jg.writeStartObject()\n          .write(\"cost\", object.getCost())\n          .write(\"vat\", object.getVat())\n          .write(\"fromDate\", sdf.format(object.getFromDate()))\n          .write(\"toDate\", sdf.format(object.getToDate()))\n          .write(\"submissionDate\", sdf2.format(object.getSubmissionDate()))\n          .write(\"type\", object.getType().toString())\n          .write(\"paid\", object.isPaid())\n          .write(\"report\", \"/objectReports/\" + reportId);\n\n        if(object.getComment() != null) {\n            jg.write(\"comment\", object.getComment());\n        }\n\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected TravelExpense getNewTransientObject(int i) {\n        TravelExpense travelExpense = new TravelExpense();\n        travelExpense.setFromDate(new Date());\n        travelExpense.setToDate(new Date());\n        travelExpense.setCost(BigDecimal.TEN);\n        travelExpense.setType(TravelExpense.Type.TAXI);\n        travelExpense.setSubmissionDate(new Date());\n        travelExpense.setVat(BigDecimal.ONE);\n        travelExpense.setComment(\"comment_\" + i);\n        return travelExpense;\n    }\n\n    @Override\n    protected TravelExpenseJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        reportId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/TravelExpenseResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.expenses;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class TravelExpenseResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private TravelExpenseJsonGenerator jsonGenerator = new TravelExpenseJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"travelExpenses\";\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\", username = \"admin@techdev.de\")\n    public void oneForbiddenForOther() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void oneAllowedForSelf() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void createAllowedForSelf() throws Exception {\n        String json = jsonGenerator.start().withReportId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void createNotAllowedForOther() throws Exception {\n        String json = jsonGenerator.start().withReportId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    public void updateAllowedForSelf() throws Exception {\n        String json = jsonGenerator.start().withReportId(0L).apply(t -> t.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    public void deletePendingAllowed() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    public void deleteAcceptedNotAllowed() throws Exception {\n        assertThat(remove(1L), isForbidden());\n    }\n\n    @Test\n    public void deleteSubmittedNotAllowed() throws Exception {\n        assertThat(remove(2L), isForbidden());\n    }\n\n    @Test\n    @Ignore\n    public void changeReportNotAllowed() throws Exception {\n        assertThat(updateLink(0L, \"report\", \"/travelExpenseReports/0\"), isForbidden());\n    }\n\n    @Test\n    public void accessTypes() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/travelExpenses/types\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class ReportJsonGenerator extends AbstractJsonGenerator<Report, ReportJsonGenerator> {\n\n    private Long employeeId;\n    private Long debitorId;\n    private Long projectId;\n\n    public ReportJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    public ReportJsonGenerator withDebitorId(Long debitorId) {\n        this.debitorId = debitorId;\n        return this;\n    }\n\n    public ReportJsonGenerator withProjectId(Long projectId) {\n        this.projectId = projectId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(Report report) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"version\", report.getVersion())\n          .write(\"status\", report.getStatus().toString());\n\n        if (employeeId != null) {\n            jg.write(\"employee\", \"/api/employees/\" + employeeId);\n        }\n\n        if (debitorId != null) {\n            jg.write(\"debitor\", \"/api/companies/\" + debitorId);\n        }\n\n        if (projectId != null) {\n            jg.write(\"project\", \"/api/projects/\" + projectId);\n        }\n\n        if (report.getSubmissionDate() != null) {\n            jg.write(\"submissionDate\", new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss\").format(report.getSubmissionDate()));\n        }\n\n        if (report.getId() != null) {\n            jg.write(\"id\", report.getId());\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected Report getNewTransientObject(int i) {\n        Report report = new Report();\n        report.setVersion(0);\n        report.setStatus(Report.Status.PENDING);\n        report.setSubmissionDate(new Date());\n\n        return report;\n    }\n\n    @Override\n    protected ReportJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        employeeId = null;\n        debitorId = null;\n        projectId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class ReportResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private ReportJsonGenerator jsonGenerator = new ReportJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"travelExpenseReports\";\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void oneAllowedForSupervisor() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void oneNotAllowedForOther() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void oneAllowedForSelf() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void createAllowed() throws Exception {\n        String json = jsonGenerator.start().withDebitorId(0L).withEmployeeId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void updateNotAllowedForSelf() throws Exception {\n        String json = jsonGenerator.start().withDebitorId(0L).withEmployeeId(0L).apply(r -> r.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @Ignore(\"yields 400 instead of 403 ?\")\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void updateForbiddenForOther() throws Exception {\n        String json = jsonGenerator.start().withDebitorId(0L).withEmployeeId(0L).apply(r -> r.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    public void deleteAllowedForOwnerIfPending() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    public void deleteForbiddenForOwnerIfSubmitted() throws Exception {\n        assertThat(remove(1L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void deleteAllowedForAdmin() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void deleteForbiddenForOtherEvenIfPending() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void pdfExport() throws Exception {\n        ResponseEntity<byte[]> response = restTemplate.getForEntity(host + \"/travelExpenseReports/0/pdf\", byte[].class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    public void pdfExportAsEmployee() throws Exception {\n        ResponseEntity<byte[]> response = restTemplate.getForEntity(host + \"/travelExpenseReports/0/pdf\", byte[].class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void updateEmployeeNotAllowedForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"employee\", \"/employees/0\"), isForbidden());\n    }\n\n    @Test\n    // TODO: Not a really useful test as expenses are never added this way (they need to have the report first...)\n    public void addTravelExpenseAllowedForSelf() throws Exception {\n        assertThat(updateLink(0L, \"expenses\", \"/travelExpenses/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void addTravelExpenseNotAllowedForOther() throws Exception {\n        assertThat(updateLink(0L, \"expenses\", \"/travelExpenses/0\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"someone.else@techdev.de\")\n    public void submitNotAllowedForOtherSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/travelExpenseReports/0/submit\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\")\n    public void approveNotAllowedForOwningSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/travelExpenseReports/0/approve\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"someone.else@techdev.de\")\n    public void approveAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/travelExpenseReports/0/approve\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"someone.else@techdev.de\")\n    public void rejectAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/travelExpenseReports/0/reject\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByStatusAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/travelExpenseReports/search/findByStatus?status=SUBMITTED\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    public void findByStatusNotAllowedForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/travelExpenseReports/search/findByStatus?status=SUBMITTED\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/ReportServiceTest.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.report;\n\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport de.techdev.trackr.domain.employee.expenses.reports.Report;\nimport de.techdev.trackr.domain.employee.expenses.reports.ReportNotifyService;\nimport de.techdev.trackr.domain.employee.expenses.reports.ReportRepository;\nimport de.techdev.trackr.domain.employee.expenses.reports.ReportService;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\n\nimport java.time.LocalDate;\nimport java.util.Date;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Matchers.any;\nimport static org.mockito.Matchers.eq;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class ReportServiceTest {\n\n    @InjectMocks\n    private ReportService service;\n\n    @Mock\n    private ReportRepository reportRepository;\n\n    @Mock\n    private EmployeeRepository employeeRepository;\n\n    @Mock\n    private ReportNotifyService reportNotifyService;\n\n    @Before\n    public void setUp() throws Exception {\n        when(reportRepository.save(any(Report.class))).then(invocation -> invocation.getArguments()[0]);\n    }\n\n    @Test\n    public void testReject() throws Exception {\n        Report travelExpenseReport = new Report();\n        travelExpenseReport.setStatus(Report.Status.SUBMITTED);\n\n        Report result = service.reject(travelExpenseReport, \"admin@techdev.de\");\n        assertThat(result.getStatus(), is(Report.Status.REJECTED));\n    }\n\n    @Test\n    public void testApprove() throws Exception {\n        Report travelExpenseReport = new Report();\n        travelExpenseReport.setStatus(Report.Status.SUBMITTED);\n\n        Report result = service.accept(travelExpenseReport, \"admin@techdev.de\");\n        assertThat(result.getStatus(), is(Report.Status.APPROVED));\n    }\n\n    @Test\n    public void testSubmit() throws Exception {\n        Report travelExpenseReport = new Report();\n        LocalDate localDate = LocalDate.of(2014, 1, 1);\n        Date date = LocalDateUtil.fromLocalDate(localDate);\n        travelExpenseReport.setStatus(Report.Status.PENDING);\n        travelExpenseReport.setSubmissionDate(date);\n\n        Report result = service.submit(travelExpenseReport);\n        assertThat(result.getStatus(), is(Report.Status.SUBMITTED));\n        assertThat(result.getSubmissionDate().after(date), is(true));\n        verify(reportNotifyService, times(1)).notifySupervisorsOnSubmission(eq(travelExpenseReport));\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.report.comment;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr.domain.employee.expenses.reports.comments.Comment;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class CommentJsonGenerator extends AbstractJsonGenerator<Comment, CommentJsonGenerator> {\n\n    private Long reportId;\n    private Long employeeId;\n\n    @Override\n    protected String getJsonRepresentation(Comment object) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss\");\n        jg.writeStartObject()\n          .write(\"text\", object.getText())\n          .write(\"employee\", \"/employees/\" + employeeId)\n          .write(\"submissionDate\", sdf.format(object.getSubmissionDate()))\n          .write(\"travelExpenseReport\", \"/travelExpenseReports/\" + reportId);\n\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    public CommentJsonGenerator withReportId(Long reportId) {\n        this.reportId = reportId;\n        return this;\n    }\n\n    public CommentJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    @Override\n    protected Comment getNewTransientObject(int i) {\n        Comment comment = new Comment();\n        comment.setSubmissionDate(new Date());\n        comment.setText(\"text_\" + i);\n        return comment;\n    }\n\n    @Override\n    protected CommentJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        reportId = null;\n        employeeId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/expenses/report/comment/CommentResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.expenses.report.comment;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class CommentResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private CommentJsonGenerator jsonGenerator = new CommentJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"travelExpenseReportComments\";\n    }\n\n    @Test\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    public void oneNotExported() throws Exception {\n        assertThat(one(0L), isMethodNotAllowed());\n    }\n\n    @Test\n    public void createAllowedForOwningEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withReportId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void createAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withReportId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\")\n    public void updateForbidden() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withReportId(0L).apply(c -> c.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\")\n    public void deleteNotExported() throws Exception {\n        assertThat(remove(0L), isMethodNotAllowed());\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/login/PrincipalControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.login;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static org.junit.Assert.assertThat;\n\n@OAuthRequest\n@Sql(\"resourceTest.sql\")\n@Sql(value = \"/de/techdev/trackr/domain/emptyDatabase.sql\", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\npublic class PrincipalControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    @Test\n    public void principal() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/principal\", String.class);\n        assertThat(response, isAccessible());\n    }\n}\n\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr.util.LocalDateUtil;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\n\npublic class SickDaysJsonGenerator extends AbstractJsonGenerator<SickDays, SickDaysJsonGenerator> {\n\n    private Long employeeId;\n\n    public SickDaysJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(SickDays object) {\n        if (employeeId == null) {\n            throw new IllegalStateException(\"employee id must not be null\");\n        }\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n          .write(\"startDate\", sdf.format(object.getStartDate()))\n          .write(\"employee\", \"/api/employees/\" + employeeId);\n        if (object.getEndDate() != null) {\n            jg.write(\"endDate\", sdf.format(object.getEndDate()));\n        }\n\n\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected SickDays getNewTransientObject(int i) {\n        SickDays sickDays = new SickDays();\n        LocalDate now = LocalDate.now();\n        sickDays.setStartDate(LocalDateUtil.fromLocalDate(now));\n        if (i % 2 == 0) {\n            sickDays.setEndDate(LocalDateUtil.fromLocalDate(now.plusDays(i)));\n        }\n        return sickDays;\n    }\n\n    @Override\n    protected SickDaysJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        employeeId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/sickdays/SickDaysResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.sickdays;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.echocat.jomon.testing.Assert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class SickDaysResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private SickDaysJsonGenerator jsonGenerator = new SickDaysJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"sickDays\";\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void rootIsNotAccessibleForAdmin() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    public void oneIsAllowedForEmployee() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void oneIsForbiddenForOther() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void createIsAllowedForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    @Ignore\n//    Not testable at the moment since it returns 400 instead of 403 (it can't convert the JSON because the employee is also restricted).\n    public void createIsForbiddenForOther() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void deleteIsAllowedForAdmin() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteIsForbiddenForSupervisor() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    public void updateIsAllowedForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(s -> s.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    // Not testable at the moment since it returns 400 instead of 403 (it can't convert the JSON because the employee is also restricted).\n    public void updateIsForbiddenForOther() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(s -> s.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    public void findByEmployeeIsAllowedForEmployee() throws Exception {\n        assertThat(oneUrl(\"/sickDays/search/findByEmployee?employee=/employees/0\"), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    @Ignore\n    // Not testable at the moment since it returns 400 instead of 403 (it can't convert the JSON because the employee is also restricted).\n    public void findByEmployeeIsForbiddenForOther() throws Exception {\n        assertThat(oneUrl(\"/sickDays/search/findByEmployee?employee=0\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void findByStartDateBetweenOrEndDateBetweenIsAllowedForAdmin() throws Exception {\n        assertThat(\n                oneUrl(\"/sickDays/search/findByStartDateBetweenOrEndDateBetween?startLower=2014-07-01&startHigher=2014-07-31&endLower=2014-07-08&endHigher=2014-08-09\"), isAccessible()\n        );\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByStartDateBetweenOrEndDateBetweenIsForbiddenForSupervisor() throws Exception {\n        assertThat(\n                oneUrl(\"/sickDays/search/findByStartDateBetweenOrEndDateBetween?startLower=2014-07-01&startHigher=2014-07-31&endLower=2014-07-08&endHigher=2014-08-09\"), isForbidden()\n        );\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayCalculatorTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.time.LocalDate;\nimport java.time.Month;\nimport java.util.List;\n\nimport static java.util.Arrays.asList;\nimport static org.echocat.jomon.testing.BaseMatchers.isTrue;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n/**\n * @author Moritz Schulze\n */\npublic class HolidayCalculatorTest {\n\n    private HolidayCalculator holidayCalculator;\n\n    @Before\n    public void setUp() throws Exception {\n        holidayCalculator = new HolidayCalculator();\n    }\n\n    @Test\n    public void calculateDifferenceBetweenExcludingHolidaysAndWeekends() throws Exception {\n        LocalDate start = LocalDate.of(2014, Month.DECEMBER, 19);\n        LocalDate end = LocalDate.of(2014, Month.DECEMBER, 31);\n        Integer numberOfDays = holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(start, end, getHolidaysAsDates());\n        assertThat(numberOfDays, is(7));\n    }\n\n    @Test\n    public void calculateDifferenceBetweenExcludingHolidaysAndWeekendsAgain() throws Exception {\n        LocalDate start = LocalDate.of(2014, Month.MARCH, 4);\n        LocalDate end = LocalDate.of(2014, Month.MARCH, 10);\n        Integer numberOfDays = holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(start, end, getHolidaysAsDates());\n        assertThat(numberOfDays, is(5));\n    }\n\n    @Test\n    public void calculateDifferenceBetweenExcludingHolidaysAndWeekendsLastDayWeekend() throws Exception {\n        LocalDate start = LocalDate.of(2014, Month.MARCH, 10);\n        LocalDate end = LocalDate.of(2014, Month.MARCH, 16);\n        Integer numberOfDays = holidayCalculator.calculateDifferenceBetweenExcludingHolidaysAndWeekends(start, end, getHolidaysAsDates());\n        assertThat(numberOfDays, is(5));\n    }\n\n    @Test\n    public void isWeekendOrHolidaySaturday() throws Exception {\n        LocalDate date = LocalDate.of(2014, Month.MARCH, 15);\n        boolean test = holidayCalculator.isWeekendOrHoliday(date, null);\n        assertThat(test, isTrue());\n    }\n\n    @Test\n    public void isWeekendOrHolidaySunday() throws Exception {\n        LocalDate date = LocalDate.of(2014, Month.MARCH, 16);\n        boolean test = holidayCalculator.isWeekendOrHoliday(date, null);\n        assertThat(test, isTrue());\n    }\n\n    @Test\n    public void isWeekendOrHolidayInList() throws Exception {\n        LocalDate date = LocalDate.of(2014, Month.DECEMBER, 25);\n        boolean test = holidayCalculator.isWeekendOrHoliday(date, getHolidaysAsDates());\n        assertThat(test, isTrue());\n    }\n\n    private List<LocalDate> getHolidaysAsDates() {\n        LocalDate holiday1 = LocalDate.of(2014, Month.DECEMBER, 25);\n        LocalDate holiday2 = LocalDate.of(2014, Month.DECEMBER, 26);\n        LocalDate holiday3 = LocalDate.of(2014, Month.OCTOBER, 3);\n        return asList(holiday1, holiday2, holiday3);\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/HolidayResourceTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isMethodNotAllowed;\nimport static org.junit.Assert.assertThat;\n\n@Sql(\"holiday/resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class HolidayResourceTest extends AbstractDomainResourceSecurityTest {\n\n    @Override\n    protected String getResourceName() {\n        return \"holidays\";\n    }\n\n    @Test\n    public void rootAccessible() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    public void oneAccessible() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void createNotExported() throws Exception {\n        assertThat(create(\"{}\"), isMethodNotAllowed());\n    }\n\n    @Test\n    public void updateNotExported() throws Exception {\n        assertThat(update(0L, \"{}\"), isMethodNotAllowed());\n    }\n\n    @Test\n    public void deleteNotExported() throws Exception {\n        assertThat(remove(0L), isMethodNotAllowed());\n    }\n\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.TestConstants;\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.http.HttpEntity;\nimport org.springframework.http.HttpMethod;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isForbidden;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;\nimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;\n\n@Sql(\"resourceTest.sql\")\n@Sql(TestConstants.CREATE_UUID_MAPPING_TABLE_SQL_FILE)\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_SUPERVISOR\")\npublic class VacationRequestControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void approveNotAllowedForSupervisorOnOwnVacationRequest() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/vacationRequests/0/approve\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isForbidden());\n        ResponseEntity<VacationRequest> vacationRequest = restTemplate.getForEntity(host + \"/vacationRequests/0\", VacationRequest.class);\n        assertThat(vacationRequest.getBody().getStatus(), is(VacationRequest.VacationRequestStatus.PENDING));\n    }\n\n    @Test\n    @OAuthRequest\n    public void approveNotAllowedForEmployees() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/vacationRequests/0/approve\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isForbidden());\n        ResponseEntity<VacationRequest> vacationRequest = restTemplate.getForEntity(host + \"/vacationRequests/0\", VacationRequest.class);\n        assertThat(vacationRequest.getBody().getStatus(), is(VacationRequest.VacationRequestStatus.PENDING));\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void approveAllowedForOtherSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/vacationRequests/0/approve\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isAccessible());\n        ResponseEntity<VacationRequest> vacationRequest = restTemplate.getForEntity(host + \"/vacationRequests/0\", VacationRequest.class);\n        assertThat(vacationRequest.getBody().getStatus(), is(VacationRequest.VacationRequestStatus.APPROVED));\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void rejectAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/vacationRequests/0/reject\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isAccessible());\n        ResponseEntity<VacationRequest> vacationRequest = restTemplate.getForEntity(host + \"/vacationRequests/0\", VacationRequest.class);\n        assertThat(vacationRequest.getBody().getStatus(), is(VacationRequest.VacationRequestStatus.REJECTED));\n    }\n\n    @Test\n    public void selfRejectForbiddenForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.exchange(host + \"/vacationRequests/0/reject\", HttpMethod.PUT, HttpEntity.EMPTY, String.class);\n        assertThat(response, isForbidden());\n        ResponseEntity<VacationRequest> vacationRequest = restTemplate.getForEntity(host + \"/vacationRequests/0\", VacationRequest.class);\n        assertThat(vacationRequest.getBody().getStatus(), is(VacationRequest.VacationRequestStatus.PENDING));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class VacationRequestJsonGenerator extends AbstractJsonGenerator<VacationRequest, VacationRequestJsonGenerator> {\n\n    private Long employeeId;\n    private Long approverId;\n\n    public VacationRequestJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    public VacationRequestJsonGenerator withApproverId(Long approverId) {\n        this.approverId = approverId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(VacationRequest object) {\n        if (employeeId == null) {\n            throw new IllegalStateException(\"Employee id must not be null\");\n        }\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        SimpleDateFormat sdf2 = new SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ss\");\n        StringWriter writer = new StringWriter();\n        JsonGenerator jsonGenerator = jsonGeneratorFactory.createGenerator(writer);\n        JsonGenerator jg = jsonGenerator\n                .writeStartObject()\n                .write(\"startDate\", sdf.format(object.getStartDate()))\n                .write(\"endDate\", sdf.format(object.getEndDate()))\n                .write(\"status\", object.getStatus().toString())\n                .write(\"employee\", \"/api/employees/\" + employeeId);\n\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        if (approverId != null) {\n            jsonGenerator.write(\"approver\", \"/api/employees/\" + approverId);\n        }\n        if (object.getApprovalDate() != null) {\n            jg.write(\"approvalDate\", sdf2.format(object.getApprovalDate()));\n        }\n        if (object.getNumberOfDays() != null) {\n            jg.write(\"numberOfDays\", object.getNumberOfDays());\n        }\n        if (object.getSubmissionTime() != null) {\n            jg.write(\"submissionTime\", sdf2.format(object.getSubmissionTime()));\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected VacationRequest getNewTransientObject(int i) {\n        VacationRequest vacationRequest = new VacationRequest();\n        vacationRequest.setStatus(VacationRequest.VacationRequestStatus.PENDING);\n        vacationRequest.setStartDate(new Date());\n        vacationRequest.setEndDate(new Date());\n        return vacationRequest;\n    }\n\n    @Override\n    protected VacationRequestJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        employeeId = null;\n        approverId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestRepositoryTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport java.time.LocalDate;\nimport java.util.Date;\nimport java.util.List;\n\nimport static org.echocat.jomon.testing.BaseMatchers.hasSize;\nimport static org.echocat.jomon.testing.BaseMatchers.isNotEmpty;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"repositoryTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\npublic class VacationRequestRepositoryTest extends TransactionalIntegrationTest {\n    \n    @Autowired\n    private VacationRequestRepository vacationRequestRepository;\n\n    @Test\n    public void findBySubmissionTimeBefore() throws Exception {\n        List<VacationRequest> all = vacationRequestRepository\n                .findBySubmissionTimeBeforeAndStatus(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 10, 16)), VacationRequest.VacationRequestStatus.PENDING);\n        assertThat(all, isNotEmpty());\n    }\n\n    @Test\n    public void findByApprovedBetween() {\n        Date start = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 10, 1));\n        Date end   = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 12, 8));\n\n        List<VacationRequest> all = vacationRequestRepository\n                .findByStartDateBetweenOrEndDateBetweenAndStatus(start, end, start, end, VacationRequest.VacationRequestStatus.APPROVED);\n        assertThat(all, hasSize(1));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport de.techdev.test.TestConstants;\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(TestConstants.CREATE_UUID_MAPPING_TABLE_SQL_FILE)\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class VacationRequestResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private VacationRequestJsonGenerator jsonGenerator = new VacationRequestJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"vacationRequests\";\n    }\n\n    @Test\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    public void oneAllowedForEmployee() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void oneForbiddenForOther() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void findByEmployeeOrderByStartDateAscAllowedForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/search/findByEmployeeOrderByStartDateAsc?employee=/employees/0\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void findByEmployeeOrderByStartDateAscAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/search/findByEmployeeOrderByStartDateAsc?employee=/employees/0\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    /**\n     * Access is forbidden, but currently spring-data-rest will throw a 400 because the employee cannot be unmarshalled from the id.\n     */\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void findByEmployeeOrderByStartDateAscForbiddenForOther() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/search/findByEmployeeOrderByStartDateAsc?employee=0\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    public void createAllowedForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void createForbiddenForSupervisorIfNotOwner() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    public void updateForbiddenForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(v -> v.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void updateAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(v -> v.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void updateSelfNotAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(v -> v.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    /**\n     * Access is forbidden, but currently spring-data-rest will throw a 400 because the employee cannot be unmarshalled from the id.\n     *\n     * @throws Exception\n     */\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void updateForbiddenForOther() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).apply(v -> v.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    public void deleteAllowedForEmployee() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"employee2@techdev.de\")\n    public void deleteApprovedNotAllowedForEmployee() throws Exception {\n        assertThat(remove(1L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"employee2@techdev.de\")\n    public void deleteRejectedNotAllowedForEmployee() throws Exception {\n        assertThat(remove(2L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void deleteAllowedForSupervisor() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteForbiddenForOwningSupervisor() throws Exception {\n        assertThat(remove(1L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void deleteForbiddenForOther() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void updateEmployeeIsForbidden() throws Exception {\n        assertThat(updateLink(0L, \"employee\", \"/employees/0\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void updateApproverIsForbidden() throws Exception {\n        assertThat(updateLink(0L, \"approver\", \"/employees/0\"), isForbidden());\n    }\n\n    @Test\n    public void deleteEmployeeIsForbidden() throws Exception {\n        assertThat(removeUrl(\"/vacationRequests/0/employee\"), isForbidden());\n    }\n\n    @Test\n    public void deleteApproverIsForbidden() throws Exception {\n        assertThat(removeUrl(\"/vacationRequests/1/approver\"), isForbidden());\n    }\n\n    @Test\n    @Ignore(\"See DATAREST-476\")\n    public void getApprover() throws Exception {\n        assertThat(oneUrl(\"/vacationRequests/1/approver\"), isAccessible());\n    }\n\n    @Test\n    public void findByStatusOrderBySubmissionTimeAscForbiddenForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/search/findByStatusOrderBySubmissionTimeAsc?approved=APPROVED\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByStatusOrderBySubmissionTimeAscAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/search/findByStatusOrderBySubmissionTimeAsc?approved=APPROVED\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void daysPerEmployeeBetweenAccessibleForAdmin() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/daysPerEmployeeBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void daysPerEmployeeBetweenForbiddenForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/vacationRequests/daysPerEmployeeBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/VacationRequestScheduledJobsTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\n\nimport static org.mockito.Mockito.*;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class VacationRequestScheduledJobsTest {\n\n    @Mock\n    private VacationRequestApproveService vacationRequestApproveService;\n\n    @InjectMocks\n    private VacationRequestScheduledJobs vacationRequestScheduledJobs;\n\n    @Test\n    public void callsTheRightMethod() throws Exception {\n        doNothing().when(vacationRequestApproveService).approveSevenDayOldRequests();\n        vacationRequestScheduledJobs.approveSevenDaysOldVacationRequests();\n        verify(vacationRequestApproveService, times(1)).approveSevenDayOldRequests();\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/support/MailApproveServiceTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\n\npublic class MailApproveServiceTest {\n\n    private MailApproveService mailApproveService;\n\n    @Before\n    public void setUp() throws Exception {\n        mailApproveService = new MailApproveService();\n    }\n\n    @Test\n    public void approveOrReject_approve() throws Exception {\n        VacationRequest.VacationRequestStatus status = mailApproveService.approveOrReject(\"approve\\nyou can answer approve or reject\");\n        assertThat(status, is(VacationRequest.VacationRequestStatus.APPROVED));\n    }\n\n    @Test\n    public void approveOrReject_reject() throws Exception {\n        VacationRequest.VacationRequestStatus status = mailApproveService.approveOrReject(\"reject\\nyou can answer approve or reject\");\n        assertThat(status, is(VacationRequest.VacationRequestStatus.REJECTED));\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void approveOrReject_exception() throws Exception {\n        mailApproveService.approveOrReject(\"you can answer approve or reject\");\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/support/MessageWrapperTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport org.junit.Test;\n\nimport javax.mail.Session;\nimport javax.mail.internet.*;\nimport java.util.Properties;\n\nimport static org.echocat.jomon.testing.BaseMatchers.isNull;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\n\npublic class MessageWrapperTest {\n\n    @Test\n    public void getSender() throws Exception {\n        MimeMessage mail = new MimeMessage(Session.getDefaultInstance(new Properties()));\n        mail.setFrom(new InternetAddress(\"test@techdev.de\"));\n        String sender = new MessageWrapper(mail).getSender();\n        assertThat(sender, is(\"test@techdev.de\"));\n    }\n\n    @Test\n    public void getSenderReturnsNullWhenNotTechdev() throws Exception {\n        MimeMessage mail = new MimeMessage(Session.getDefaultInstance(new Properties()));\n        mail.setFrom(new InternetAddress(\"test@gmail.de\"));\n        String sender = new MessageWrapper(mail).getSender();\n        assertThat(sender, isNull());\n    }\n\n    @Test\n    public void getBodyPlaintext() throws Exception {\n        MimeMessage mail = new MimeMessage(Session.getDefaultInstance(new Properties()));\n        mail.setContent(\"Test\", \"text/plain\");\n        String body = new MessageWrapper(mail).extractContentAsString();\n        assertThat(body, is(\"Test\"));\n    }\n\n    @Test\n    public void getBodyMimeMultipart() throws Exception {\n        MimeMessage mail = new MimeMessage(Session.getDefaultInstance(new Properties()));\n        MimeMultipart mimeMultipart = new MimeMultipart();\n\n        MimeBodyPart plainTextPart = new MimeBodyPart(new InternetHeaders(), \"Test\".getBytes());\n        plainTextPart.setContent(\"Test\", \"text/plain\");\n        mimeMultipart.addBodyPart(plainTextPart);\n\n        MimeBodyPart otherPart = new MimeBodyPart(new InternetHeaders(), \"Other\".getBytes());\n        otherPart.setContent(\"<b>Other</b>\", \"text/html\");\n        mimeMultipart.addBodyPart(otherPart);\n\n        mail.setContent(mimeMultipart);\n        String body = new MessageWrapper(mail).extractContentAsString();\n        assertThat(body, is(\"Test\"));\n    }\n\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestEmployeeToDaysTotalServiceTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.time.LocalDate;\nimport java.util.Date;\nimport java.util.Map;\n\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class VacationRequestEmployeeToDaysTotalServiceTest {\n\n    VacationRequestEmployeeToDaysTotalService service;\n\n    @Before\n    public void setUp() throws Exception {\n        service = new VacationRequestEmployeeToDaysTotalService();\n    }\n\n    @Test\n    public void testGetMinimum() throws Exception {\n        Date date1 = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 7, 1));\n        Date date2 = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 7, 2));\n        Date minimum = service.getMinimum(date1, date2);\n        assertThat(minimum, is(date1));\n    }\n\n    @Test\n    public void testGetMaximum() throws Exception {\n        Date date1 = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 7, 1));\n        Date date2 = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 7, 2));\n        Date maximum = service.getMaximum(date1, date2);\n        assertThat(maximum, is(date2));\n    }\n\n    @Test\n    public void mapEmployeesAndSumUp() throws Exception {\n        Employee empl1 = new Employee();\n        empl1.setFirstName(\"first_name_1\");\n        empl1.setLastName(\"last_name_1\");\n        Employee empl2 = new Employee();\n        empl2.setFirstName(\"first_name_2\");\n        empl2.setLastName(\"last_name_2\");\n        VacationRequest vr1 = new VacationRequest();\n        vr1.setEmployee(empl1);\n        VacationRequest vr2 = new VacationRequest();\n        vr2.setEmployee(empl1);\n        VacationRequest vr3 = new VacationRequest();\n        vr3.setEmployee(empl2);\n\n        Map<String, Integer> employeeDayMapping = service.mapToEmployeesAndSumUp(asList(vr1, vr2, vr3), vr -> 1);\n        assertThat(employeeDayMapping.keySet().size(), is(2));\n        assertThat(employeeDayMapping.get(\"first_name_1 last_name_1\"), is(2));\n        assertThat(employeeDayMapping.get(\"first_name_2 last_name_2\"), is(1));\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/vacation/support/VacationRequestNotifyServiceTest.java",
    "content": "package de.techdev.trackr.domain.employee.vacation.support;\n\nimport de.techdev.trackr.core.mail.MailService;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.vacation.VacationRequest;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\nimport org.springframework.mail.SimpleMailMessage;\n\nimport static org.echocat.jomon.testing.StringMatchers.contains;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class VacationRequestNotifyServiceTest {\n\n    @InjectMocks\n    private VacationRequestNotifyService vacationRequestNotifyService;\n\n    @Mock\n    private MailService mailService;\n\n    private VacationRequest vacationRequest;\n\n    @Before\n    public void setUp() throws Exception {\n        vacationRequest = new VacationRequest();\n        Employee employee = new Employee();\n        employee.setEmail(\"employee@techdev.de\");\n        vacationRequest.setEmployee(employee);\n    }\n\n    @Test\n    public void sendNotificationApproved() throws Exception {\n        ArgumentCaptor<SimpleMailMessage> mail = ArgumentCaptor.forClass(SimpleMailMessage.class);\n\n        vacationRequest.setStatus(VacationRequest.VacationRequestStatus.APPROVED);\n        vacationRequestNotifyService.sendEmailNotification(vacationRequest);\n        verify(mailService, times(1)).sendMail(mail.capture());\n\n        assertThat(mail.getValue().getSubject(), contains(\"approved\"));\n    }\n\n    @Test\n    public void sendNotificationRejected() throws Exception {\n        ArgumentCaptor<SimpleMailMessage> mail = ArgumentCaptor.forClass(SimpleMailMessage.class);\n\n        vacationRequest.setStatus(VacationRequest.VacationRequestStatus.REJECTED);\n        vacationRequestNotifyService.sendEmailNotification(vacationRequest);\n        verify(mailService, times(1)).sendMail(mail.capture());\n\n        assertThat(mail.getValue().getSubject(), contains(\"rejected\"));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/employee/worktimetracking/WorkTimeTrackingReminderServiceIntegrationTest.java",
    "content": "package de.techdev.trackr.domain.employee.worktimetracking;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.techdev.trackr.domain.ApiBeansConfiguration;\nimport de.techdev.trackr.domain.common.FederalState;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.ContextConfiguration;\n\n@ContextConfiguration(classes = {ApiBeansConfiguration.class})\npublic class WorkTimeTrackingReminderServiceIntegrationTest extends TransactionalIntegrationTest {\n\n    @Autowired\n    private WorkTimeTrackingReminderService workTimeTrackingReminderService;\n\n    @Test\n    public void remindEmployeesToTrackWorkTimes() throws Exception {\n        workTimeTrackingReminderService.remindEmployeesToTrackWorkTimes(FederalState.BERLIN);\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/ProjectJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\n\npublic class ProjectJsonGenerator extends AbstractJsonGenerator<Project, ProjectJsonGenerator> {\n\n    private Long companyId;\n    private Long debitorId;\n\n    public ProjectJsonGenerator withCompanyId(Long companyId) {\n        this.companyId = companyId;\n        return this;\n    }\n\n    public ProjectJsonGenerator withDebitorId(Long debitorId) {\n        this.debitorId = debitorId;\n        return this;\n    }\n\n    @Override\n    protected Project getNewTransientObject(int i) {\n        Project project = new Project();\n        project.setVersion(0);\n        project.setIdentifier(\"identifier_\" + i);\n        project.setName(\"name_\" + i);\n        project.setDailyRate(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setFixedPrice(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setHourlyRate(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setVolume(i);\n        return project;\n    }\n\n    @Override\n    protected void reset() {\n        companyId = null;\n        debitorId = null;\n    }\n\n    @Override\n    protected String getJsonRepresentation(Project project) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        jg.writeStartObject()\n          .write(\"name\", project.getName())\n          .write(\"version\", project.getVersion())\n          .write(\"identifier\", project.getIdentifier())\n          .write(\"volume\", project.getVolume())\n          .write(\"hourlyCostRate\", project.getDailyRate())\n          .write(\"salary\", project.getHourlyRate())\n          .write(\"title\", project.getFixedPrice());\n\n        if (debitorId != null) {\n            jg.write(\"company\", \"/api/companies/\" + companyId);\n        }\n\n        if (companyId != null) {\n            jg.write(\"debitor\", \"/api/companies/\" + debitorId);\n        }\n\n        if (project.getId() != null) {\n            jg.write(\"id\", project.getId());\n        }\n\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected ProjectJsonGenerator getSelf() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/ProjectResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.project;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport java.math.BigDecimal;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_ADMIN\")\npublic class ProjectResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private ProjectJsonGenerator jsonGenerator = new ProjectJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"projects\";\n    }\n\n    @Test\n    @OAuthRequest\n    public void rootAccessible() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest\n    public void one() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void createAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void updateAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().apply(p -> p.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    public void deleteAllowedForAdmin() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void createForbiddenForSupervisor() throws Exception {\n        String json = jsonGenerator.start().build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\")\n    public void updateForbiddenForSupervisor() throws Exception {\n        String json = jsonGenerator.start().apply(p -> p.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteForbiddenForSupervisor() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    public void setCompanyAllowedForAdmin() throws Exception {\n        assertThat(updateLink(0L, \"company\", \"/companies/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void setCompanyForbiddenForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"company\", \"/companies/0\"), isForbidden());\n    }\n\n    @Test\n    public void setDebitorAllowedForAdmin() throws Exception {\n        assertThat(updateLink(0L, \"debitor\", \"/companies/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void setDebitorForbiddenForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"debitor\", \"/companies/0\"), isForbidden());\n    }\n\n    @Test\n    public void setWorktimesAllowedForAdmin() throws Exception {\n        assertThat(updateLink(0L, \"workTimes\", \"/workTimes/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void setWorktimesForbiddenForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"workTimes\", \"/workTimes/0\"), isForbidden());\n    }\n\n    @Test\n    public void deleteCompanyAllowedForAdmin() throws Exception {\n        assertThat(removeUrl(\"/projects/0/company\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteCompanyForbiddenForSupervisor() throws Exception {\n        assertThat(removeUrl(\"/projects/0/company\"), isForbidden());\n    }\n\n    @Test\n    public void deleteDebitorAllowedForAdmin() throws Exception {\n        assertThat(removeUrl(\"/projects/0/debitor\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteDebitorForbiddenForSupervisor() throws Exception {\n        assertThat(removeUrl(\"/projects/0/debitor\"), isForbidden());\n    }\n\n    @Test\n    public void deleteWorktimesAllowedForAdmin() throws Exception {\n        assertThat(removeUrl(\"/projects/0/workTimes/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteWorktimesForbiddenForSupervisor() throws Exception {\n        assertThat(removeUrl(\"/projects/0/workTimes/0\"), isForbidden());\n    }\n\n    public Project getNewTransientObject(int i) {\n        Project project = new Project();\n        project.setIdentifier(\"identifier_\" + i);\n        project.setName(\"name_\" + i);\n        project.setDailyRate(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setFixedPrice(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setHourlyRate(BigDecimal.TEN.multiply(new BigDecimal(i)));\n        project.setVolume(i);\n        return project;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimeControllerIntegrationTest.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isForbidden;\nimport static org.junit.Assert.assertThat;\n\npublic class BillableTimeControllerIntegrationTest extends AbstractRestIntegrationTest {\n\n    @Test\n    @OAuthRequest\n    public void findEmployeeMappingByProjectAndDateBetweenForbiddenForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/billableTimes/findEmployeeMappingByProjectAndDateBetween?project=0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findEmployeeMappingByProjectAndDateBetweenAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/billableTimes/findEmployeeMappingByProjectAndDateBetween?project=0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimeResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class BillableTimeResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private BillableTimesJsonGenerator jsonGenerator = new BillableTimesJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"billableTimes\";\n    }\n\n    @Test\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void oneAllowedForSupervisor() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    public void oneForbiddenForEmployee() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void createAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void createForbiddenForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void deleteAllowedForSupervisor() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    public void deleteForbiddenForEmployee() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void updateAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).apply(b -> b.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    /**\n     * TODO: this fails with HTTP 400 because findOne is annotated with @PreAuthorize and spring-data-rest doesn't forward the AccessDeniedException correctly\n     */\n    @Test\n    @Ignore\n    public void updateForbiddenForEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).apply(b -> b.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void deleteEmployeeForbidden() throws Exception {\n        assertThat(removeUrl(\"/billableTimes/0/employee\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void deleteProjectForbidden() throws Exception {\n        assertThat(removeUrl(\"/billableTimes/0/project\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void updateEmployeeAllowedForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"employee\", \"/employees/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void updateProjectAllowedForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"project\", \"/projects/0\"), isNoContent());\n    }\n\n    @Test\n    public void updateEmployeeForbiddenForEmployee() throws Exception {\n        assertThat(updateLink(0L, \"employee\", \"/employees/0\"), isForbidden());\n    }\n\n    @Test\n    public void updateProjectForbiddenForEmployee() throws Exception {\n        assertThat(updateLink(0L, \"project\", \"/projects/0\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_ADMIN\")\n    public void findByDateBetweenAllowedForAdmin() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/billableTimes/search/findByDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByDateBetweenForbiddenForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/billableTimes/search/findByDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/billtimes/BillableTimesJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.project.billtimes;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\nimport de.techdev.trackr.util.LocalDateUtil;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.time.temporal.ChronoField;\n\npublic class BillableTimesJsonGenerator extends AbstractJsonGenerator<BillableTime, BillableTimesJsonGenerator> {\n\n    private Long employeeId;\n    private Long projectId;\n\n    public BillableTimesJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    public BillableTimesJsonGenerator withProjectId(Long projectId) {\n        this.projectId = projectId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(BillableTime object) {\n        StringWriter writer = new StringWriter();\n        if (employeeId == null || projectId == null) {\n            throw new IllegalStateException(\"Employee id and project id must not be null.\");\n        }\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n          .write(\"date\", sdf.format(object.getDate()))\n          .write(\"minutes\", object.getMinutes())\n          .write(\"employee\", \"/employees/\" + employeeId)\n          .write(\"project\", \"/projects/\" + projectId);\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected BillableTime getNewTransientObject(int i) {\n        BillableTime billableTime = new BillableTime();\n        LocalDate localDate = LocalDate.now().with(ChronoField.DAY_OF_YEAR, (i % 356) + 1);\n        billableTime.setDate(LocalDateUtil.fromLocalDate(localDate));\n        billableTime.setMinutes(i);\n        return billableTime;\n    }\n\n    @Override\n    protected BillableTimesJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        employeeId = null;\n        projectId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceEventHandlerTest.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.trackr.domain.company.Company;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.time.LocalDate;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.*;\n\npublic class InvoiceEventHandlerTest {\n\n    private InvoiceEventHandler invoiceEventHandler;\n\n    @Before\n    public void setUp() throws Exception {\n        invoiceEventHandler = new InvoiceEventHandler();\n    }\n\n    @Test\n    public void testSetInvoiceStateIfNecessaryOverdue() throws Exception {\n        Invoice invoice = new Invoice();\n        LocalDate dueDate = LocalDate.of(2013, 10, 1);\n        invoice.setDueDate(LocalDateUtil.fromLocalDate(dueDate));\n        invoiceEventHandler.setInvoiceStateIfNecessary(invoice);\n        assertThat(invoice.getInvoiceState(), is(Invoice.InvoiceState.OVERDUE));\n    }\n\n    @Test\n    public void testSetInvoiceStateIfNecessaryOutstanding() throws Exception {\n        Invoice invoice = new Invoice();\n        LocalDate dueDate = LocalDate.now().plusDays(7);\n        invoice.setDueDate(LocalDateUtil.fromLocalDate(dueDate));\n        invoiceEventHandler.setInvoiceStateIfNecessary(invoice);\n        assertThat(invoice.getInvoiceState(), is(Invoice.InvoiceState.OUTSTANDING));\n    }\n\n    @Test\n    public void testSetDueDateFromTimeForPayment() throws Exception {\n        Invoice invoice = new Invoice();\n        Company company = new Company();\n        company.setTimeForPayment(14);\n        invoice.setDebitor(company);\n        invoice.setCreationDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n\n        invoiceEventHandler.setDueDateFromTimeForPayment(invoice);\n        assertThat(invoice.getDueDate(), is(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 15))));\n    }\n\n    @Test\n    public void testDontSetDueDateFromTimeForPaymentIfItIsFilled() throws Exception {\n        Invoice invoice = new Invoice();\n        Company company = new Company();\n        company.setTimeForPayment(14);\n        invoice.setDebitor(company);\n        invoice.setCreationDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n        invoice.setDueDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 2)));\n\n        invoiceEventHandler.setDueDateFromTimeForPayment(invoice);\n        assertThat(invoice.getDueDate(), is(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 2))));\n    }\n\n    @Test\n    public void testSetDueDateFromTimeForPaymentDontFailOnNoDebitor() throws Exception {\n        Invoice invoice = new Invoice();\n        invoice.setCreationDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n        invoiceEventHandler.setDueDateFromTimeForPayment(invoice);\n    }\n\n    @Test\n    public void testSetDueDateFromTimeForPaymentDontFailOnNoTimeForPayment() throws Exception {\n        Invoice invoice = new Invoice();\n        Company company = new Company();\n        invoice.setDebitor(company);\n        invoice.setCreationDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n\n        invoiceEventHandler.setDueDateFromTimeForPayment(invoice);\n    }\n\n    @Test\n    public void stateGetsSetToOverdueIfTimeForPaymentSetsDueDateInPast() throws Exception {\n        Invoice invoice = new Invoice();\n        Company company = new Company();\n        company.setTimeForPayment(14);\n        invoice.setDebitor(company);\n        invoice.setCreationDate(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 1)));\n\n        invoiceEventHandler.authorizeCreate(invoice);\n        assertThat(invoice.getDueDate(), is(LocalDateUtil.fromLocalDate(LocalDate.of(2014, 1, 15))));\n        assertThat(invoice.getInvoiceState(), is(Invoice.InvoiceState.OVERDUE));\n    }\n}"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.math.BigDecimal;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class InvoiceJsonGenerator extends AbstractJsonGenerator<Invoice, InvoiceJsonGenerator> {\n\n    private Long debitorId;\n\n    public InvoiceJsonGenerator withDebitorId(Long debitorId) {\n        this.debitorId = debitorId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(Invoice object) {\n        StringWriter writer = new StringWriter();\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n          .write(\"identifier\", object.getIdentifier())\n          .write(\"invoiceState\", object.getInvoiceState().toString())\n          .write(\"invoiceTotal\", object.getInvoiceTotal())\n          .write(\"debitor\", \"/companies/\" + debitorId)\n          .write(\"creationDate\", sdf.format(object.getCreationDate()));\n\n        if (object.getDueDate() != null) {\n            jg.write(\"dueDate\", sdf.format(object.getDueDate()));\n        }\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected Invoice getNewTransientObject(int i) {\n        Invoice invoice = new Invoice();\n        invoice.setIdentifier(\"identifier_\" + i);\n        invoice.setInvoiceState(Invoice.InvoiceState.OUTSTANDING);\n        invoice.setDueDate(new Date());\n        invoice.setInvoiceTotal(BigDecimal.TEN);\n        invoice.setCreationDate(new Date());\n        return invoice;\n    }\n\n    @Override\n    protected InvoiceJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        debitorId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/invoice/InvoiceResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.project.invoice;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest(\"ROLE_ADMIN\")\npublic class InvoiceResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private InvoiceJsonGenerator jsonGenerator = new InvoiceJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"invoices\";\n    }\n\n    @Test\n    public void rootIsAccessibleForAdmin() throws Exception {\n        assertThat(root(), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void rootIsForbiddenForSupervisor() throws Exception {\n        assertThat(root(), isForbidden());\n    }\n\n    @Test\n    public void oneIsAccessibleForAdmin() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void oneIsForbiddenForSupervisor() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void findByInvoiceStateIsAccessibleForAdmin() throws Exception {\n        assertThat(oneUrl(\"/invoices/search/findByInvoiceState?state=OUTSTANDING\"), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByInvoiceStateIsForbiddenForSupervisor() throws Exception {\n        assertThat(oneUrl(\"/invoices/search/findByInvoiceState?state=OUTSTANDING\"), isForbidden());\n    }\n\n    @Test\n    public void findByIdentifierLikeAndInvoiceStateIsAccessibleForAdmin() throws Exception {\n        assertThat(oneUrl(\"/invoices/search/findByIdentifierLikeIgnoreCaseAndInvoiceState?identifier=TEST&state=OUTSTANDING\"), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByIdentifierLikeAndInvoiceStateIsForbiddenForSupervisor() throws Exception {\n        assertThat(oneUrl(\"/invoices/search/findByIdentifierLikeIgnoreCaseAndInvoiceState?identifier=TEST&state=OUTSTANDING\"), isForbidden());\n    }\n\n    @Test\n    public void findByCreationDateBetweenAccessibleForAdmin() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/invoices/search/findByCreationDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findByCreationDateBetweenForbiddenForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/invoices/search/findByCreationDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    public void adminCanCreate() throws Exception {\n        String json = jsonGenerator.start().withDebitorId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void supervisorCannotCreate() throws Exception {\n        String json = jsonGenerator.start().withDebitorId(0L).build();\n        assertThat(create(json), isForbidden());\n    }\n\n    @Test\n    public void adminCanDelete() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void supervisorCannotDelete() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    @Test\n    public void adminCanSetPaid() throws Exception {\n        ResponseEntity<String> response = restTemplate.postForEntity(host + \"/invoices/0/markPaid\", null, String.class);\n        assertThat(response, isAccessible());\n        ResponseEntity<Invoice> invoice = restTemplate.getForEntity(host + \"/invoices/0\", Invoice.class);\n        assertThat(invoice.getBody().getInvoiceState(), is(Invoice.InvoiceState.PAID));\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void supervisorCannotSetPaid() throws Exception {\n        ResponseEntity<String> response = restTemplate.postForEntity(host + \"/invoices/0/markPaid\", null, String.class);\n        assertThat(response, isForbidden());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/CustomWorkTimeTest.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport org.junit.Test;\n\nimport java.sql.Time;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.List;\n\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\npublic class CustomWorkTimeTest {\n    @Test\n    public void reduceAndSortWorktimes() throws Exception {\n        List<CustomWorkTime> reduced = CustomWorkTime.reduceAndSortWorktimes(createCustomWorkTimes());\n        assertThat(reduced.size(), is(2));\n        assertThat(reduced.get(0).getEnteredMinutes(), is(300L));\n        assertThat(reduced.get(1).getEnteredMinutes(), is(480L));\n    }\n\n    @Test\n    public void reduceAndSortWorkTimesPreservesComments() throws Exception {\n        List<CustomWorkTime> reduced = CustomWorkTime.reduceAndSortWorktimes(createCustomWorkTimes());\n        assertThat(reduced.get(0).getComment(), is(\"Hallo1\\nHallo2\"));\n        assertThat(reduced.get(1).getComment(), is(\"Hallo3\"));\n    }\n\n    private List<CustomWorkTime> createCustomWorkTimes() throws ParseException {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        CustomWorkTime ctw1 = new CustomWorkTime();\n        ctw1.setDate(sdf.parse(\"2014-01-01\"));\n        ctw1.setEnteredMinutes(240L);\n        ctw1.setComment(\"Hallo1\");\n        CustomWorkTime ctw2 = new CustomWorkTime();\n        ctw2.setDate(sdf.parse(\"2014-01-01\"));\n        ctw2.setComment(\"Hallo2\");\n        ctw2.setEnteredMinutes(60L);\n        CustomWorkTime ctw3 = new CustomWorkTime();\n        ctw3.setComment(\"Hallo3\");\n        ctw3.setDate(sdf.parse(\"2014-01-02\"));\n        ctw3.setEnteredMinutes(480L);\n        return asList(ctw1, ctw2, ctw3);\n    }\n\n    @Test\n    public void customWorkTimeHourCalculation() throws Exception {\n        WorkTime workTime21 = new WorkTime();\n        workTime21.setDate(new Date());\n        workTime21.setStartTime(Time.valueOf(\"09:00:00\"));\n        workTime21.setEndTime(Time.valueOf(\"17:00:00\"));\n        CustomWorkTime customWorkTime = CustomWorkTime.valueOf(workTime21);\n        assertThat(customWorkTime.getEnteredMinutes(), is(480L));\n    }\n\n    @Test\n    public void customWorkTimeTransfersTheCommentFromTheWorkTime() throws Exception {\n        WorkTime workTime21 = new WorkTime();\n        workTime21.setDate(new Date());\n        workTime21.setComment(\"Hallo\");\n        workTime21.setStartTime(Time.valueOf(\"09:00:00\"));\n        workTime21.setEndTime(Time.valueOf(\"17:00:00\"));\n        CustomWorkTime customWorkTime = CustomWorkTime.valueOf(workTime21);\n        assertThat(customWorkTime.getComment(), is(\"Hallo\"));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isForbidden;\nimport static org.junit.Assert.assertThat;\nimport static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;\n\n@OAuthRequest\npublic class WorkTimeControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    @Test\n    public void findEmployeeMappingByProjectAndDateBetweenForbiddenForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/findEmployeeMappingByProjectAndDateBetween?project=0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(\"ROLE_SUPERVISOR\")\n    public void findEmployeeMappingByProjectAndDateBetweenAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/findEmployeeMappingByProjectAndDateBetween?project=0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeControllerTest.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.trackr.domain.employee.Employee;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Matchers;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\nimport org.springframework.hateoas.EntityLinks;\nimport org.springframework.hateoas.Link;\n\nimport java.sql.Time;\nimport java.text.SimpleDateFormat;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static java.util.Arrays.asList;\nimport static org.echocat.jomon.testing.BaseMatchers.isNotNull;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\n/**\n * @author Moritz Schulze\n */\n@RunWith(MockitoJUnitRunner.class)\npublic class WorkTimeControllerTest {\n\n    @InjectMocks\n    private WorkTimeController workTimeController;\n\n    @Mock\n    private EntityLinks entityLinks;\n\n    @Test\n    public void convertStreamOfWorkTimesToMap() throws Exception {\n        Link link = mock(Link.class);\n        when(link.withSelfRel()).thenReturn(link);\n        when(entityLinks.linkToSingleResource(Matchers.any(), Matchers.any())).thenReturn(link);\n        Map<Long, WorkTimeEmployee> map = workTimeController.convertStreamOfWorkTimesToMap(createTestWorktimes(), new HashMap<>());\n        assertThat(\"The map must contain two employee mappings\", map.keySet().size(), is(2));\n        assertThat(\"One mapping must be for id 1\", map.get(1L), isNotNull());\n        assertThat(\"One mapping must be for id 2\", map.get(2L), isNotNull());\n        assertThat(\"The mapping for id 1 must have two work times\", map.get(1L).getWorkTimes().size(), is(2));\n        assertThat(\"The mapping for id 2 must have one work time\", map.get(2L).getWorkTimes().size(), is(1));\n    }\n\n    private List<WorkTime> createTestWorktimes() throws Exception {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        Employee employee1 = new Employee();\n        employee1.setId(1L);\n        employee1.setFirstName(\"employee_1\");\n        employee1.setLastName(\"employee_1\");\n\n        Employee employee2 = new Employee();\n        employee2.setId(2L);\n        employee2.setFirstName(\"employee_2\");\n        employee2.setLastName(\"employee_2\");\n\n        WorkTime workTime11 = new WorkTime();\n        workTime11.setEmployee(employee1);\n        workTime11.setDate(sdf.parse(\"2014-01-01\"));\n        workTime11.setStartTime(Time.valueOf(\"09:00:00\"));\n        workTime11.setEndTime(Time.valueOf(\"15:00:00\"));\n\n        WorkTime workTime12 = new WorkTime();\n        workTime12.setEmployee(employee1);\n        workTime12.setDate(sdf.parse(\"2014-02-02\"));\n        workTime12.setStartTime(Time.valueOf(\"16:00:00\"));\n        workTime12.setEndTime(Time.valueOf(\"17:00:00\"));\n\n        WorkTime workTime21 = new WorkTime();\n        workTime21.setEmployee(employee2);\n        workTime21.setDate(sdf.parse(\"2014-01-01\"));\n        workTime21.setStartTime(Time.valueOf(\"09:00:00\"));\n        workTime21.setEndTime(Time.valueOf(\"17:00:00\"));\n        return asList(workTime11, workTime12, workTime21);\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeJsonGenerator.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.test.rest.AbstractJsonGenerator;\n\nimport javax.json.stream.JsonGenerator;\nimport java.io.StringWriter;\nimport java.sql.Time;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class WorkTimeJsonGenerator extends AbstractJsonGenerator<WorkTime, WorkTimeJsonGenerator> {\n\n    private Long employeeId;\n    private Long projectId;\n\n    public WorkTimeJsonGenerator withEmployeeId(Long employeeId) {\n        this.employeeId = employeeId;\n        return this;\n    }\n\n    public WorkTimeJsonGenerator withProjectId(Long projectId) {\n        this.projectId = projectId;\n        return this;\n    }\n\n    @Override\n    protected String getJsonRepresentation(WorkTime object) {\n        StringWriter writer = new StringWriter();\n        if (projectId == null || employeeId == null) {\n            throw new IllegalStateException(\"employee id and project id must be set!\");\n        }\n        JsonGenerator jg = jsonGeneratorFactory.createGenerator(writer);\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd\");\n        jg.writeStartObject()\n          .write(\"date\", sdf.format(object.getDate()))\n          .write(\"startTime\", object.getStartTime().toString())\n          .write(\"endTime\", object.getEndTime().toString())\n          .write(\"employee\", \"/employees/\" + employeeId)\n          .write(\"project\", \"/projects/\" + projectId);\n\n        if (object.getComment() != null) {\n            jg.write(\"comment\", object.getComment());\n        }\n\n        if (object.getId() != null) {\n            jg.write(\"id\", object.getId());\n        }\n        jg.writeEnd().close();\n        return writer.toString();\n    }\n\n    @Override\n    protected WorkTime getNewTransientObject(int i) {\n        WorkTime workTime = new WorkTime();\n        workTime.setDate(new Date());\n        workTime.setStartTime(Time.valueOf(\"09:00:00\"));\n        workTime.setEndTime(Time.valueOf(\"17:00:00\"));\n        workTime.setComment(\"comment_\" + i);\n        return workTime;\n    }\n\n    @Override\n    protected WorkTimeJsonGenerator getSelf() {\n        return this;\n    }\n\n    @Override\n    protected void reset() {\n        projectId = null;\n        employeeId = null;\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeRepositoryTest.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.test.TransactionalIntegrationTest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport de.techdev.trackr.domain.employee.Employee;\nimport de.techdev.trackr.domain.employee.EmployeeRepository;\nimport de.techdev.trackr.domain.project.Project;\nimport de.techdev.trackr.domain.project.ProjectRepository;\nimport de.techdev.trackr.util.LocalDateUtil;\nimport org.junit.Test;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport java.text.SimpleDateFormat;\nimport java.time.LocalDate;\nimport java.util.Date;\nimport java.util.List;\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n\n@Sql(\"repositoryTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\npublic class WorkTimeRepositoryTest extends TransactionalIntegrationTest {\n\n    @Autowired\n    private WorkTimeRepository workTimeRepository;\n\n    @Autowired\n    private EmployeeRepository employeeRepository;\n\n    @Autowired\n    private ProjectRepository projectRepository;\n\n    /**\n     * This finder must only respect the date but not time part of the second parameter.\n     */\n    @Test\n    public void findByEmployeeAndDateOnlyRespectsDatePart() throws Exception {\n        SimpleDateFormat sdf = new SimpleDateFormat(\"yyyy-MM-dd HH:mm\");\n        Employee employee = employeeRepository.findOne(0L);\n        List<WorkTime> workTimes = workTimeRepository.findByEmployeeAndDateOrderByStartTimeAsc(employee, sdf.parse(\"2014-03-04 09:00:00\"));\n        assertThat(workTimes.size(), is(2));\n    }\n\n    @Test\n    public void findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc() throws Exception {\n        Employee employee = employeeRepository.findOne(0L);\n\n        Date low = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 3, 4));\n        Date high = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 3, 5));\n\n        List<WorkTime> all = workTimeRepository.findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc(employee, low, high);\n        assertThat(all.size(), is(3));\n    }\n\n    @Test\n    public void findByProjectAndDateBetweenOrderByDateAscStartTimeAsc() throws Exception {\n        Project project = projectRepository.findOne(0L);\n\n        Date low = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 3, 4));\n        Date high = LocalDateUtil.fromLocalDate(LocalDate.of(2014, 3, 5));\n\n        List<WorkTime> all = workTimeRepository.findByProjectAndDateBetweenOrderByDateAscStartTimeAsc(project, low, high);\n        assertThat(all.size(), is(3));\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/project/worktimes/WorkTimeResourceSecurityTest.java",
    "content": "package de.techdev.trackr.domain.project.worktimes;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractDomainResourceSecurityTest;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\nimport org.springframework.test.context.jdbc.Sql;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.*;\nimport static org.hamcrest.MatcherAssert.assertThat;\n\n@Sql(\"resourceTest.sql\")\n@Sql(value = AbstractDomainResourceSecurityTest.EMPTY_DATABASE_FILE, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)\n@OAuthRequest\npublic class WorkTimeResourceSecurityTest extends AbstractDomainResourceSecurityTest {\n\n    private WorkTimeJsonGenerator jsonGenerator = new WorkTimeJsonGenerator();\n\n    @Override\n    protected String getResourceName() {\n        return \"workTimes\";\n    }\n\n    @Test\n    public void rootNotExported() throws Exception {\n        assertThat(root(), isMethodNotAllowed());\n    }\n\n    @Test\n    public void oneAllowedForOwner() throws Exception {\n        assertThat(one(0L), isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void oneForbiddenForOther() throws Exception {\n        assertThat(one(0L), isForbidden());\n    }\n\n    @Test\n    public void createAllowedForEveryoneIfIsEmployee() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).build();\n        assertThat(create(json), isCreated());\n    }\n\n    @Test\n    public void updateAllowedForOwner() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).apply(w -> w.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\", username = \"admin@techdev.de\")\n    public void updateAllowedForAdmin() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).apply(w -> w.setId(0L)).build();\n        assertThat(update(0L, json), isUpdated());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void updateNotAllowedForSupervisor() throws Exception {\n        String json = jsonGenerator.start().withEmployeeId(0L).withProjectId(0L).apply(w -> w.setId(0L)).build();\n        assertThat(update(0L, json), isForbidden());\n    }\n\n    @Test\n    public void deleteAllowedForOwner() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\", username = \"admin@techdev.de\")\n    public void deleteAllowedForAdmin() throws Exception {\n        assertThat(remove(0L), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void deleteNotAllowedForSupervisor() throws Exception {\n        assertThat(remove(0L), isForbidden());\n    }\n\n    /**\n     * TODO: when trying to set to another employee the EmployeeRepository will deny accessing that employee which will result in a HTTP 400\n     * TODO: When trying to set to the same employee our Exception thrown in the {@link de.techdev.trackr.domain.project.worktimes.WorkTimeEventHandler}\n     * TODO: won't be propagated to Web MVC.\n     * TODO: so in conclusion updating does not work but will produce a 500 or 400 instead of a 405.\n     * @throws Exception\n     */\n    @Test\n    @Ignore\n    public void updateEmployeeNotAllowed() throws Exception {\n        assertThat(updateLink(0L, \"employee\", \"/employees/0\"), isMethodNotAllowed());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\")\n    public void deleteEmployeeNotAllowed() throws Exception {\n        assertThat(removeUrl(\"/workTimes/0/employee\"), isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\")\n    public void deleteProjectNotAllowed() throws Exception {\n        assertThat(removeUrl(\"/workTimes/0/project\"), isForbidden());\n    }\n\n    @Test\n    public void updateProjectAllowedForOwner() throws Exception {\n        assertThat(updateLink(0L, \"project\", \"/projects/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\", username = \"admin@techdev.de\")\n    public void updateProjectAllowedForAdmin() throws Exception {\n        assertThat(updateLink(0L, \"project\", \"/projects/0\"), isNoContent());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void updateProjectForbiddenForSupervisor() throws Exception {\n        assertThat(updateLink(0L, \"project\", \"/projects/0\"), isForbidden());\n    }\n\n    @Test\n    public void findByEmployeeAndDateOrderByStartTimeAscAllowedForOwner() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateOrderByStartTimeAsc?employee=/employees/0&date=2014-01-01\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void findByEmployeeAndDateOrderByStartTimeAscAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateOrderByStartTimeAsc?employee=/employees/0&date=2014-01-01\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_ADMIN\")\n    public void findByDateBetweenAllowedForAdmin() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void findByDateBetweenForbiddenForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByDateBetween?start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    public void findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscAllowedForOwner() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc?employee=/employees/0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\", username = \"supervisor@techdev.de\")\n    public void findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc?employee=/employees/0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    /**\n     * This does not work because the accessDeniedException is thrown somewhere where spring-data-rest does not catch it.\n     * So we get HTTP 400 instead of 403.\n     * TODO: find out how to get a 403\n     */\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void findByEmployeeAndDateBetweenOrderByDateAscStartTimeAscForbiddenForOther() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateBetweenOrderByDateAscStartTimeAsc?employee=/employees/0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    /**\n     * This does not work because the accessDeniedException is thrown somewhere where spring-data-rest does not catch it.\n     * So we get HTTP 400 instead of 403.\n     * TODO: find out how to get a 403\n     */\n    @Test\n    @Ignore\n    @OAuthRequest(username = \"someone.else@techdev.de\")\n    public void findByEmployeeAndDateOrderByStartTimeAscForbiddenForOther() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByEmployeeAndDateOrderByStartTimeAsc?employee=/employees/0&date=2014-01-01\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n    @Test\n    @OAuthRequest(value = \"ROLE_SUPERVISOR\")\n    public void findByProjectAndDateBetweenOrderByDateAscStartTimeAscAllowedForSupervisor() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByProjectAndDateBetweenOrderByDateAscStartTimeAsc?project=/projects/0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isAccessible());\n    }\n\n    @Test\n    public void findByProjectAndDateBetweenOrderByDateAscStartTimeAscForbiddenForEmployee() throws Exception {\n        ResponseEntity<String> response = restTemplate\n                .getForEntity(host + \"/workTimes/search/findByProjectAndDateBetweenOrderByDateAscStartTimeAsc?project=/projects/0&start=2014-01-01&end=2014-01-31\", String.class);\n        assertThat(response, isForbidden());\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/scheduling/LastWorkdayDayOfMonthTriggerTest.java",
    "content": "package de.techdev.trackr.domain.scheduling;\n\nimport de.techdev.trackr.domain.common.FederalState;\nimport de.techdev.trackr.domain.employee.vacation.Holiday;\nimport de.techdev.trackr.domain.employee.vacation.HolidayRepository;\nimport de.techdev.trackr.domain.scheduling.LastWorkdayDayOfMonthTrigger;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Matchers;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\nimport org.springframework.scheduling.TriggerContext;\n\nimport java.time.DayOfWeek;\nimport java.time.LocalDate;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\n\nimport static de.techdev.trackr.util.LocalDateUtil.fromDate;\nimport static de.techdev.trackr.util.LocalDateUtil.fromLocalDate;\nimport static java.util.Arrays.asList;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.MatcherAssert.assertThat;\nimport static org.mockito.Mockito.when;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class LastWorkdayDayOfMonthTriggerTest {\n\n    @InjectMocks\n    private LastWorkdayDayOfMonthTrigger lastWorkdayDayOfMonthTrigger = new LastWorkdayDayOfMonthTrigger();\n\n    @Mock\n    private HolidayRepository holidayRepository;\n\n    private List<LocalDate> holidays;\n\n    @Before\n    public void setUp() throws Exception {\n        lastWorkdayDayOfMonthTrigger.setFederalState(FederalState.BERLIN);\n        Holiday holiday = new Holiday();\n        holiday.setDay(fromLocalDate(LocalDate.of(2014, 5, 1)));\n        List<Holiday> holidayList = new ArrayList<>();\n        holidayList.add(holiday);\n        when(holidayRepository.findByFederalStateAndDayBetween(Matchers.any(), Matchers.any(), Matchers.any())).thenReturn(holidayList);\n\n        holidays = new ArrayList<>();\n        holidays.add(fromDate(holiday.getDay()));\n    }\n\n    @Test\n    public void lastDayIsNotWeekend() throws Exception {\n        LocalDate march2014 = LocalDate.of(2014, 3, 1);\n        LocalDate lastWeekdayInMonth = lastWorkdayDayOfMonthTrigger.lastWeekdayInMonth(march2014, holidays);\n        assertThat(lastWeekdayInMonth.getDayOfWeek(), is(DayOfWeek.MONDAY));\n    }\n\n    @Test\n    public void lastDayIsSunday() throws Exception {\n        LocalDate march2014 = LocalDate.of(2014, 8, 5);\n        LocalDate lastWeekdayInMonth = lastWorkdayDayOfMonthTrigger.lastWeekdayInMonth(march2014, holidays);\n        assertThat(lastWeekdayInMonth.getDayOfWeek(), is(DayOfWeek.FRIDAY));\n    }\n\n    @Test\n    public void lastDayIsSaturday() throws Exception {\n        LocalDate march2014 = LocalDate.of(2014, 5, 2);\n        LocalDate lastWeekdayInMonth = lastWorkdayDayOfMonthTrigger.lastWeekdayInMonth(march2014, holidays);\n        assertThat(lastWeekdayInMonth.getDayOfWeek(), is(DayOfWeek.FRIDAY));\n    }\n\n    @Test\n    public void lastDayIsMondayAndHoliday() throws Exception {\n        LocalDate june2014 = LocalDate.of(2014, 6, 1);\n        List<LocalDate> holidays = asList(LocalDate.of(2014, 6, 30));\n        LocalDate lastWeekDayInMonth = lastWorkdayDayOfMonthTrigger.lastWeekdayInMonth(june2014, holidays);\n        assertThat(lastWeekDayInMonth.getDayOfWeek(), is(DayOfWeek.FRIDAY));\n        assertThat(lastWeekDayInMonth.getDayOfMonth(), is(27));\n    }\n\n    @Test\n    public void lastDayIsMondayAndHolidayAndTheFridayIsAHolidayToo() throws Exception {\n        LocalDate june2014 = LocalDate.of(2014, 6, 1);\n        List<LocalDate> holidays = asList(LocalDate.of(2014, 6, 27), LocalDate.of(2014, 6, 30));\n        LocalDate lastWeekDayInMonth = lastWorkdayDayOfMonthTrigger.lastWeekdayInMonth(june2014, holidays);\n        assertThat(lastWeekDayInMonth.getDayOfWeek(), is(DayOfWeek.THURSDAY));\n        assertThat(lastWeekDayInMonth.getDayOfMonth(), is(26));\n    }\n\n    @Test\n    public void triggerThisMonthIfLastScheduledTimeIsNull() throws Exception {\n        LocalDate date = lastWorkdayDayOfMonthTrigger.nextExecutionTimeInternal(\n                getTriggerContextWithLastScheduledExecutionTime(null));\n        assertThat(date.getMonth(), is(LocalDate.now().getMonth()));\n    }\n\n    @Test\n    public void dontTriggerTwiceAMonth() throws Exception {\n        LocalDate date = lastWorkdayDayOfMonthTrigger.nextExecutionTimeInternal(\n                getTriggerContextWithLastScheduledExecutionTime(fromLocalDate(LocalDate.now())));\n        assertThat(date.getMonth(), is(LocalDate.now().plusMonths(1).getMonth()));\n    }\n\n    protected TriggerContext getTriggerContextWithLastScheduledExecutionTime(final Date time) {\n        return new TriggerContext() {\n            @Override\n            public Date lastScheduledExecutionTime() {\n                return time;\n            }\n\n            @Override\n            public Date lastActualExecutionTime() {\n                return null;\n            }\n\n            @Override\n            public Date lastCompletionTime() {\n                return null;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/translations/TranslationControllerSecurityTest.java",
    "content": "package de.techdev.trackr.domain.translations;\n\nimport de.techdev.test.oauth.OAuthRequest;\nimport de.techdev.test.rest.AbstractRestIntegrationTest;\nimport org.junit.Test;\nimport org.springframework.http.ResponseEntity;\n\nimport static de.techdev.test.rest.DomainResourceTestMatchers.isAccessible;\nimport static org.junit.Assert.assertThat;\n\n@OAuthRequest\npublic class TranslationControllerSecurityTest extends AbstractRestIntegrationTest {\n\n    @Test\n    public void testGetTranslationsIsAccessible() throws Exception {\n        ResponseEntity<String> response = restTemplate.getForEntity(host + \"/translations?locale=de\", String.class);\n        assertThat(response, isAccessible());\n    }\n}\n"
  },
  {
    "path": "src/test/java/de/techdev/trackr/domain/translations/TranslationControllerTest.java",
    "content": "package de.techdev.trackr.domain.translations;\n\nimport de.techdev.trackr.domain.employee.SettingsRepository;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.InjectMocks;\nimport org.mockito.Mock;\nimport org.mockito.runners.MockitoJUnitRunner;\nimport org.springframework.mock.web.MockHttpServletRequest;\nimport org.springframework.mock.web.MockHttpServletResponse;\nimport org.springframework.web.servlet.LocaleResolver;\n\nimport java.util.Locale;\n\nimport static org.echocat.jomon.testing.BaseMatchers.isNotEmpty;\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.junit.Assert.assertThat;\nimport static org.mockito.Mockito.atLeastOnce;\nimport static org.mockito.Mockito.verify;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class TranslationControllerTest {\n\n    @InjectMocks\n    private TranslationController translationController;\n\n    @Mock\n    private LocaleResolver localeResolver;\n\n    @Mock\n    private SettingsRepository settingsRepository;\n\n    @Test\n    public void testGetTranslations() throws Exception {\n        MockHttpServletResponse response = new MockHttpServletResponse();\n        translationController.getTranslations(Locale.ENGLISH, response);\n        assertThat(response.getStatus(), is(200));\n        assertThat(response.getContentAsString(), isNotEmpty());\n    }\n\n    @Test\n    public void testSetTranslations() throws Exception {\n        MockHttpServletRequest request = new MockHttpServletRequest();\n        MockHttpServletResponse response = new MockHttpServletResponse();\n        translationController.setLocale(Locale.ENGLISH, request, response, () -> \"admin\");\n\n        verify(localeResolver, atLeastOnce()).setLocale(request, response, Locale.ENGLISH);\n    }\n}"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/company/address/resourceTest.sql",
    "content": "-- data for the address resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/company/contactPerson/resourceTest.sql",
    "content": "-- data for the contact person resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, roles, company) VALUES (0, 0, 'Robert', 'Lake', 'r.lake@webshop.de', 'Mr', '0178/11234566', 'Sales Manager', 0);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/company/repositoryTest.sql",
    "content": "-- data for the company repository test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, roles, company)\n  VALUES (0, 0, 'Robert', 'Lake', 'r.lake@webshop.de', 'Mr', '0178/11234566', 'Sales Manager', 0);\n\n--- with project\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (1, 0, 1001, 'webshop Ltd.', 0, 30);\n\nINSERT INTO project (id, dailyrate, fixedprice, hourlyrate, identifier, name, version, volume, company_id)\n  VALUES (0, 30, 30, 30, '1001.1', 'Project', 0, 1000, 1);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/company/resourceTest.sql",
    "content": "-- data for the company resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO contactPerson (id, version, firstName, lastName, email, salutation, phone, roles, company) VALUES (0, 0, 'Robert', 'Lake', 'r.lake@webshop.de', 'Mr', '0178/11234566', 'Sales Manager', 0);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/expenses/report/comment/resourceTest.sql",
    "content": "-- data for the travel expense report comment resource test\nINSERT INTO employee (id, federalstate, firstname, hourlycostrate, joindate, lastname, phonenumber, salary, title, vacationentitlement, version, email, deleted)\n VALUES (0, 'BERLIN', 'Firstname', 100, '2014-06-06', 'Lastname', 'Phonenumber', 40000, 'Title', 30, 0, 'employee@techdev.de', false);\n\nINSERT INTO address (id, city, country, housenumber, street, version, zipcode)\n  VALUES (0, 'City', 'Country', '13', 'Street', 0, 'zipcode');\n\nINSERT INTO company (id, companyid, name, version, address_id, timeforpayment)\n  VALUES (0, 1000, 'Company', 0, 0, 30);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n  VALUES (0, 0, 0, 'PENDING', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelexpensereportcomment (id, submissiondate, text, employee_id, travelexpensereport_id)\n  VALUES (0, '2015-01-25 13:01:31', 'Comment 1', 0, 0);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/expenses/report/resourceTest.sql",
    "content": "-- data for travel expense report resource test\nINSERT INTO employee (id, federalstate, firstname, hourlycostrate, joindate, lastname, phonenumber, salary, title, vacationentitlement, version, email, deleted)\n VALUES (0, 'BERLIN', 'Firstname', 100, '2014-06-06', 'Lastname', 'Phonenumber', 40000, 'Title', 30, 0, 'employee@techdev.de', false);\n\nINSERT INTO employee (id, federalstate, firstname, hourlycostrate, joindate, lastname, phonenumber, salary, title, vacationentitlement, version, email, deleted)\n VALUES (1, 'BERLIN', 'Firstname', 100, '2014-06-06', 'Lastname', 'Phonenumber', 40000, 'Title', 30, 0, 'someone.else@techdev.de', false);\n\nINSERT INTO address (id, city, country, housenumber, street, version, zipcode)\n VALUES (0, 'City', 'Country', '13', 'Street', 0, 'zipcode');\n\nINSERT INTO company (id, companyid, name, version, address_id, timeforpayment)\n VALUES (0, 1000, 'Company', 0, 0, 30);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n VALUES (0, 0, 0, 'PENDING', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n VALUES (1, 0, 0, 'SUBMITTED', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelexpense (id, cost, fromdate, submissiondate, todate, type, vat, version, report_id, comment, paid)\n  VALUES (0, 100, '2015-01-01', '2015-02-01 13:41:13', '2015-02-13', 'TAXI', 13, 0, 0, 'Comment', false);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/expenses/resourceTest.sql",
    "content": "-- data for the travel expense report comment resource test\nINSERT INTO employee (id, federalstate, firstname, hourlycostrate, joindate, lastname, phonenumber, salary, title, vacationentitlement, version, email, deleted)\n VALUES (0, 'BERLIN', 'Firstname', 100, '2014-06-06', 'Lastname', 'Phonenumber', 40000, 'Title', 30, 0, 'employee@techdev.de', false);\n\nINSERT INTO address (id, city, country, housenumber, street, version, zipcode)\n  VALUES (0, 'City', 'Country', '13', 'Street', 0, 'zipcode');\n\nINSERT INTO company (id, companyid, name, version, address_id, timeforpayment)\n  VALUES (0, 1000, 'Company', 0, 0, 30);\n\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n  VALUES (0, 0, 0, 'PENDING', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelexpense (id, cost, fromdate, submissiondate, todate, type, vat, version, report_id, comment, paid)\n  VALUES (0, 100, '2015-01-01', '2015-02-01 13:41:13', '2015-02-13', 'TAXI', 13, 0, 0, 'Comment', false);\n\n-- accepted report for various tests\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n  VALUES (1, 0, 0, 'APPROVED', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelexpense (id, cost, fromdate, submissiondate, todate, type, vat, version, report_id, comment, paid)\n  VALUES (1, 100, '2015-01-01', '2015-02-01 13:41:13', '2015-02-13', 'TAXI', 13, 0, 1, 'Comment', false);\n\n-- submitted report for various tests\nINSERT INTO travelExpenseReport (id, version, employee_id, status, submissionDate, debitor_id)\n  VALUES (2, 0, 0, 'SUBMITTED', '2015-01-25 09:30:21', 0);\n\nINSERT INTO travelexpense (id, cost, fromdate, submissiondate, todate, type, vat, version, report_id, comment, paid)\n  VALUES (2, 100, '2015-01-01', '2015-02-01 13:41:13', '2015-02-13', 'TAXI', 13, 0, 2, 'Comment', true);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/login/resourceTest.sql",
    "content": "-- data for the principal controller resource test.\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\nINSERT INTO settings (id, type, value, employee_id)\n  VALUES (0, 'LOCALE', 'en', 0)"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/resourceTest.sql",
    "content": "-- data for the employee resource test.\nINSERT INTO address (id, city, country, housenumber, street, version, zipcode) VALUES (0, 'Berlin', 'Deutschland', '11', 'Berliner Strasse', 0, '10111');\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, address_id, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, 0, false);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/sickdays/resourceTest.sql",
    "content": "-- data for the sick days resource test.\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\nINSERT INTO sickdays (id, enddate, startdate, version, employee_id) VALUES (0, '2014-01-05', '2014-01-01', 0, 0);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/vacation/holiday/resourceTest.sql",
    "content": "-- data for the holiday resource test.\nINSERT INTO holiday (id, day, federalstate, name) VALUES (0, '2014-12-24', 'BERLIN', 'Weihnachten');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/vacation/repositoryTest.sql",
    "content": "-- data for the vacation request repository test.\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id)\n  VALUES (0, '2014-12-08', 5, '2014-10-01', 'APPROVED', '2014-10-15 19:21:56', 0, 0);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id)\n  VALUES (1, '2014-12-08', 5, '2014-10-01', 'REJECTED', '2014-10-15 19:21:56', 0, 0);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id)\n  VALUES (3, '2014-12-08', 5, '2014-10-01', 'PENDING', '2014-10-15 19:21:56', 0, 0);"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/employee/vacation/resourceTest.sql",
    "content": "-- data for the vacation request resource test.\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id)\n  VALUES (0, '2015-02-06', 5, '2015-02-02', 'PENDING', '2015-01-20 19:21:56', 0, 0);\n\n-- approved and rejected requests for various tests\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (1, 0, 'employee2@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id, approvaldate, approver_id)\n  VALUES (1, '2015-02-06', 5, '2015-02-02', 'APPROVED', '2015-01-20 19:21:56', 0, 0, '2015-01-21 09:13:47', 1);\n\nINSERT INTO vacationrequest (id, enddate, numberofdays, startdate, status, submissiontime, version, employee_id, approvaldate, approver_id)\n  VALUES (2, '2015-02-06', 5, '2015-02-02', 'REJECTED', '2015-01-20 19:21:56', 0, 0, '2015-01-21 09:13:47', 1);\n"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/emptyDatabase.sql",
    "content": "DELETE FROM billabletime;\nDELETE FROM contactperson;\nDELETE FROM holiday;\nDELETE FROM invoice;\nDELETE FROM settings;\nDELETE FROM sickdays;\nDELETE FROM travelexpense;\nDELETE FROM travelexpensereportcomment;\nDELETE FROM travelexpensereport;\nDELETE FROM vacationrequest;\nDELETE FROM worktime;\nDELETE FROM project;\nDELETE FROM company;\nDELETE FROM employee;\nDELETE FROM address;\n"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/project/billtimes/resourceTest.sql",
    "content": "-- data for the billable time resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO project (id, version, identifier, name, company_id, volume, fixedPrice) VALUES (0, 0, '1000.2014.1', 'Webshop - Checkout Development', 0, 60, 15000);\n\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO billabletime (id, date, minutes, version, employee, project) VALUES (0L, '2015-01-01', 680, 0, 0, 0);\n"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/project/invoice/resourceTest.sql",
    "content": "-- data for the project resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO invoice (id, version, identifier, debitor, creationDate, invoiceTotal, invoiceState, dueDate) VALUES (0, 0, '1003.2014.1-2014.01-1', 0, '2014-01-04', 1500.00, 'PAID', '2014-02-01');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/project/resourceTest.sql",
    "content": "-- data for the project resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (1, 0, 'Berliner Straße', '125', '60139', 'Frankfurt', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\nINSERT INTO company (id, version, companyId, name, address_id) VALUES (1, 0, 1001, 'finance Meier & partners', 1);\n\nINSERT INTO project (id, version, identifier, name, company_id, volume, fixedPrice, debitor_id) VALUES (0, 0, '1000.2014.1', 'Webshop - Checkout Development', 0, 60, 15000, 1);\n\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (1, 0, 0, 0, '2014-06-02', '09:00:00', '17:15:00');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/project/worktimes/repositoryTest.sql",
    "content": "-- data for the worktime repository test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO project (id, version, identifier, name, company_id, volume, fixedPrice) VALUES (0, 0, '1000.2014.1', 'Webshop - Checkout Development', 0, 60, 15000);\n\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (0, 0, 0, 0, '2014-03-04', '11:00:00', '18:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (1, 0, 0, 0, '2014-03-04', '12:00:00', '15:00:00');\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (2, 0, 0, 0, '2014-03-05', '12:00:00', '15:00:00');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/project/worktimes/resourceTest.sql",
    "content": "-- data for the worktime resource test.\nINSERT INTO address (id, version, street, houseNumber, zipCode, city, country) VALUES (0, 0, 'Sun Alley', '31', '15489', 'Munich', 'Deutschland');\n\nINSERT INTO company (id, version, companyId, name, address_id, timeForPayment) VALUES (0, 0, 1000, 'webshop Ltd.', 0, 30);\n\nINSERT INTO project (id, version, identifier, name, company_id, volume, fixedPrice) VALUES (0, 0, '1000.2014.1', 'Webshop - Checkout Development', 0, 60, 15000);\n\nINSERT INTO employee (id, version, email, firstName, lastName, title, hourlyCostRate, salary, federalState, joinDate, vacationEntitlement, deleted)\n  VALUES (0, 0, 'employee@techdev.de', 'John', 'Johnson', 'Software Engineer', 80, 10000, 'BERLIN', '2014-02-01', 30, false);\n\nINSERT INTO worktime (id, version, project, employee, date, startTime, endTime) VALUES (0, 0, 0, 0, '2014-06-02', '09:00:00', '17:15:00');"
  },
  {
    "path": "src/test/resources/de/techdev/trackr/domain/tableUuidMapping.sql",
    "content": "CREATE TABLE IF NOT EXISTS uuid_mapping (\n  id int8 not null,\n  uuid varchar(40)\n);"
  }
]