diff --git a/service/build.gradle.kts b/service/build.gradle.kts index 4414e861..3f2613c8 100644 --- a/service/build.gradle.kts +++ b/service/build.gradle.kts @@ -12,7 +12,7 @@ plugins { kotlin("jvm") version "2.1.0" kotlin("plugin.spring") version "2.1.0" id("org.flywaydb.flyway") version "11.0.0" - id("org.jlleitschuh.gradle.ktlint") version "12.1.0" + id("org.jlleitschuh.gradle.ktlint") version "12.1.2" id("org.owasp.dependencycheck") version "11.1.0" idea @@ -45,6 +45,10 @@ idea { } } +ktlint { + version.set("1.4.1") +} + dependencies { api(kotlin("stdlib")) implementation("org.jetbrains.kotlin:kotlin-reflect") @@ -116,12 +120,10 @@ tasks.register("resolveDependencies") { it.isCanBeResolved && // ignore configurations that fetch sources (e.g. Java source code) !it.name.endsWith("dependencySources", ignoreCase = true) - } - .map { + }.map { val files = it.resolve() it.name to files.size - } - .groupBy({ (_, count) -> count }) { (name, _) -> name } + }.groupBy({ (_, count) -> count }) { (name, _) -> name } .forEach { (count, names) -> println( "Resolved $count dependency files for configurations: ${names.joinToString(", ")}" diff --git a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/PlaywrightTest.kt b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/PlaywrightTest.kt index 3820be50..1dca4419 100644 --- a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/PlaywrightTest.kt +++ b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/PlaywrightTest.kt @@ -55,7 +55,8 @@ abstract class PlaywrightTest { playwright = Playwright.create() browser = playwright.chromium().launch( - BrowserType.LaunchOptions() + BrowserType + .LaunchOptions() .setHeadless(runningInDocker) .setTimeout(10_000.0) ) diff --git a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/CreateStudentPage.kt b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/CreateStudentPage.kt index fb8f805b..6dce3b1e 100644 --- a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/CreateStudentPage.kt +++ b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/CreateStudentPage.kt @@ -9,7 +9,9 @@ import com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat import fi.espoo.oppivelvollisuus.baseUrl import fi.espoo.oppivelvollisuus.dataQa -class CreateStudentPage(private val page: Page) { +class CreateStudentPage( + private val page: Page +) { val saveButton = page.locator(dataQa("save-button")) val dateOfBirthInput = page.locator(dataQa("date-of-birth-input")) val lastNameInput = page.locator(dataQa("last-name-input")) diff --git a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/LoginPage.kt b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/LoginPage.kt index aaef8bb1..d9d36f0e 100644 --- a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/LoginPage.kt +++ b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/LoginPage.kt @@ -9,7 +9,9 @@ import com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat import fi.espoo.oppivelvollisuus.baseUrl import fi.espoo.oppivelvollisuus.dataQa -class LoginPage(private val page: Page) { +class LoginPage( + private val page: Page +) { val startLoginButton = page.locator(dataQa("start-login")) val loggedInUser = page.locator(dataQa("logged-in-user")) diff --git a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentPage.kt b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentPage.kt index 24d341e1..43069c06 100644 --- a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentPage.kt +++ b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentPage.kt @@ -10,7 +10,9 @@ import fi.espoo.oppivelvollisuus.baseUrl import fi.espoo.oppivelvollisuus.dataQa import java.util.regex.Pattern -class StudentPage(private val page: Page) { +class StudentPage( + private val page: Page +) { val studentName = page.locator(dataQa("student-name")) fun assertUrl() { diff --git a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentsSearchPage.kt b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentsSearchPage.kt index 342cd434..44d9c0d8 100644 --- a/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentsSearchPage.kt +++ b/service/src/e2eTest/kotlin/fi/espoo/oppivelvollisuus/pages/StudentsSearchPage.kt @@ -9,7 +9,9 @@ import com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat import fi.espoo.oppivelvollisuus.baseUrl import fi.espoo.oppivelvollisuus.dataQa -class StudentsSearchPage(private val page: Page) { +class StudentsSearchPage( + private val page: Page +) { val createStudentButton = page.locator(dataQa("create-student-button")) fun assertUrl() { diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/SystemController.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/SystemController.kt index e641e29b..ee352f8d 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/SystemController.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/SystemController.kt @@ -37,16 +37,13 @@ class SystemController { @PostMapping("/user-login") fun userLogin( @RequestBody adUser: AdUser - ): AppUser { - return jdbi.inTransactionUnchecked { it.upsertAppUserFromAd(adUser) }.also { + ): AppUser = + jdbi.inTransactionUnchecked { it.upsertAppUserFromAd(adUser) }.also { logger.audit(AuthenticatedUser(it.id), "USER_LOGIN") } - } @GetMapping("/users/{id}") fun getUser( @PathVariable id: UUID - ): AppUser? { - return jdbi.inTransactionUnchecked { it.getAppUser(id) } - } + ): AppUser? = jdbi.inTransactionUnchecked { it.getAppUser(id) } } diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/common/AppUser.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/common/AppUser.kt index 548c860f..a7a46022 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/common/AppUser.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/common/AppUser.kt @@ -40,10 +40,8 @@ VALUES (:externalId, :firstName, :lastName, :email) ON CONFLICT (external_id) DO UPDATE SET updated = now(), first_names = :firstName, last_name = :lastName, email = :email RETURNING id, external_id, first_name, last_name, email - """ - .trimIndent() - ) - .bindKotlin(adUser) + """.trimIndent() + ).bindKotlin(adUser) .mapTo() .one() @@ -63,10 +61,8 @@ fun Handle.getAppUser(id: UUID) = SELECT id, external_id, first_name, last_name, email FROM users WHERE id = :id AND NOT system_user - """ - .trimIndent() - ) - .bind("id", id) + """.trimIndent() + ).bind("id", id) .mapTo() .findOne() .getOrNull() diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/Auth.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/Auth.kt index 6adc0cec..9ce28824 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/Auth.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/Auth.kt @@ -69,7 +69,9 @@ class HttpAccessControl : HttpFilter() { } } -class JwtTokenDecoder(private val jwtVerifier: JWTVerifier) : HttpFilter() { +class JwtTokenDecoder( + private val jwtVerifier: JWTVerifier +) : HttpFilter() { private val logger = KotlinLogging.logger {} override fun doFilter( @@ -78,7 +80,8 @@ class JwtTokenDecoder(private val jwtVerifier: JWTVerifier) : HttpFilter() { chain: FilterChain ) { try { - request.getBearerToken() + request + .getBearerToken() ?.takeIf { it.isNotEmpty() } ?.let { request.setDecodedJwt(jwtVerifier.verify(it)) } } catch (e: JWTVerificationException) { diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/ExceptionHandler.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/ExceptionHandler.kt index b03d8a40..37082f31 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/ExceptionHandler.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/ExceptionHandler.kt @@ -35,7 +35,8 @@ class ExceptionHandler : ResponseEntityExceptionHandler() { ex: BadRequest ): ResponseEntity { logger.warn("Bad request (${ex.message})", ex) - return ResponseEntity.status(HttpStatus.BAD_REQUEST) + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) .body(ErrorResponse(errorCode = ex.errorCode)) } @@ -45,7 +46,8 @@ class ExceptionHandler : ResponseEntityExceptionHandler() { ex: NotFound ): ResponseEntity { logger.warn("Not found (${ex.message})", ex) - return ResponseEntity.status(HttpStatus.NOT_FOUND) + return ResponseEntity + .status(HttpStatus.NOT_FOUND) .body(ErrorResponse(errorCode = ex.errorCode)) } @@ -55,7 +57,8 @@ class ExceptionHandler : ResponseEntityExceptionHandler() { ex: Conflict ): ResponseEntity { logger.warn("fi.espoo.oppivelvollisuus.common.Conflict (${ex.message})", ex) - return ResponseEntity.status(HttpStatus.CONFLICT) + return ResponseEntity + .status(HttpStatus.CONFLICT) .body(ErrorResponse(errorCode = ex.errorCode)) } @@ -65,7 +68,8 @@ class ExceptionHandler : ResponseEntityExceptionHandler() { ex: Unauthorized ): ResponseEntity { logger.warn("fi.espoo.oppivelvollisuus.common.Unauthorized (${ex.message})", ex) - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + return ResponseEntity + .status(HttpStatus.UNAUTHORIZED) .body(ErrorResponse(errorCode = ex.errorCode)) } @@ -75,7 +79,8 @@ class ExceptionHandler : ResponseEntityExceptionHandler() { ex: Forbidden ): ResponseEntity { logger.warn("fi.espoo.oppivelvollisuus.common.Forbidden (${ex.message})", ex) - return ResponseEntity.status(HttpStatus.FORBIDDEN) + return ResponseEntity + .status(HttpStatus.FORBIDDEN) .body(ErrorResponse(errorCode = ex.errorCode)) } diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JacksonConfig.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JacksonConfig.kt index f9d6cac6..a6bac631 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JacksonConfig.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JacksonConfig.kt @@ -17,16 +17,17 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration fun defaultJsonMapperBuilder(): JsonMapper.Builder = - JsonMapper.builder() + JsonMapper + .builder() .addModules( - KotlinModule.Builder() + KotlinModule + .Builder() .enable(KotlinFeature.SingletonSupport) .build(), JavaTimeModule(), Jdk8Module(), ParameterNamesModule() - ) - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + ).disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) @Configuration class JacksonConfig { diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JwtConfig.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JwtConfig.kt index 025fb28e..970a3ddf 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JwtConfig.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/JwtConfig.kt @@ -26,7 +26,11 @@ import java.security.spec.RSAPublicKeySpec class JwtConfig { @Bean fun rsaJwtAlgorithm(env: AppEnv): Algorithm { - val publicKeys = env.jwt.publicKeysUrl.toURL().openStream().use { loadPublicKeys(it) } + val publicKeys = + env.jwt.publicKeysUrl + .toURL() + .openStream() + .use { loadPublicKeys(it) } return Algorithm.RSA256(JwtKeys(publicKeys)) } @@ -34,7 +38,9 @@ class JwtConfig { fun jwtVerifier(algorithm: Algorithm): JWTVerifier = JWT.require(algorithm).acceptLeeway(1).build() } -class JwtKeys(private val publicKeys: Map) : RSAKeyProvider { +class JwtKeys( + private val publicKeys: Map +) : RSAKeyProvider { override fun getPrivateKeyId(): String? = null override fun getPrivateKey(): RSAPrivateKey? = null @@ -44,15 +50,23 @@ class JwtKeys(private val publicKeys: Map) : RSAKeyProvide fun loadPublicKeys(inputStream: InputStream): Map { @JsonIgnoreProperties(ignoreUnknown = true) - class Jwk(val kid: String, val n: ByteArray, val e: ByteArray) + class Jwk( + val kid: String, + val n: ByteArray, + val e: ByteArray + ) - class JwkSet(val keys: List) + class JwkSet( + val keys: List + ) val kf = KeyFactory.getInstance("RSA") return jacksonMapperBuilder() .defaultBase64Variant(Base64Variants.MODIFIED_FOR_URL) .build() - .readValue(inputStream).keys.associate { + .readValue(inputStream) + .keys + .associate { it.kid to kf.generatePublic( RSAPublicKeySpec( diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SpringMvcConfig.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SpringMvcConfig.kt index c4000ae7..7a7705a3 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SpringMvcConfig.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SpringMvcConfig.kt @@ -25,9 +25,8 @@ class SpringMvcConfig : WebMvcConfigurer { } object AuthenticatedUserResolver : HandlerMethodArgumentResolver { - override fun supportsParameter(parameter: MethodParameter): Boolean { - return AuthenticatedUser::class.java.isAssignableFrom(parameter.parameterType) - } + override fun supportsParameter(parameter: MethodParameter): Boolean = + AuthenticatedUser::class.java.isAssignableFrom(parameter.parameterType) override fun resolveArgument( parameter: MethodParameter, diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SsnMasker.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SsnMasker.kt index 996c9d24..75da9cca 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SsnMasker.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/config/SsnMasker.kt @@ -11,8 +11,8 @@ class SsnMasker : ValueMasker { override fun mask( context: JsonStreamContext?, value: Any? - ): Any { - return if (value is String) { + ): Any = + if (value is String) { value.replace( Regex( "(? - val studentId = tx.insertStudent(data = body.student, user = user) - tx.insertStudentCase(studentId = studentId, data = body.studentCase, user = user) + ): UUID = + jdbi + .inTransactionUnchecked { tx -> + val studentId = tx.insertStudent(data = body.student, user = user) + tx.insertStudentCase(studentId = studentId, data = body.studentCase, user = user) - studentId - }.also { - logger.audit( - user, - "CREATE_STUDENT" - ) - } - } + studentId + }.also { + logger.audit( + user, + "CREATE_STUDENT" + ) + } @PostMapping("/students/duplicates") fun getDuplicateStudents( user: AuthenticatedUser, @RequestBody body: DuplicateStudentCheckInput - ): List { - return jdbi.inTransactionUnchecked { tx -> - tx.getPossibleDuplicateStudents(body) - }.also { - logger.audit( - user, - "GET_DUPLICATE_STUDENTS" - ) - } - } + ): List = + jdbi + .inTransactionUnchecked { tx -> + tx.getPossibleDuplicateStudents(body) + }.also { + logger.audit( + user, + "GET_DUPLICATE_STUDENTS" + ) + } @PostMapping("/students/search") fun getStudents( user: AuthenticatedUser, @RequestBody body: StudentSearchParams - ): List { - return jdbi.inTransactionUnchecked { tx -> - tx.getStudentSummaries( - params = - body.copy( - query = body.query.takeIf { !it.isNullOrBlank() } - ) - ) - }.also { - logger.audit( - user, - "SEARCH_STUDENTS" - ) - } - } + ): List = + jdbi + .inTransactionUnchecked { tx -> + tx.getStudentSummaries( + params = + body.copy( + query = body.query.takeIf { !it.isNullOrBlank() } + ) + ) + }.also { + logger.audit( + user, + "SEARCH_STUDENTS" + ) + } data class StudentResponse( val student: Student, @@ -97,19 +97,19 @@ class AppController { fun getStudent( user: AuthenticatedUser, @PathVariable id: UUID - ): StudentResponse { - return jdbi.inTransactionUnchecked { tx -> - val studentDetails = tx.getStudent(id = id) - val cases = tx.getStudentCasesByStudent(studentId = id) - StudentResponse(studentDetails, cases) - }.also { - logger.audit( - user, - "GET_STUDENT", - mapOf("studentId" to id.toString()) - ) - } - } + ): StudentResponse = + jdbi + .inTransactionUnchecked { tx -> + val studentDetails = tx.getStudent(id = id) + val cases = tx.getStudentCasesByStudent(studentId = id) + StudentResponse(studentDetails, cases) + }.also { + logger.audit( + user, + "GET_STUDENT", + mapOf("studentId" to id.toString()) + ) + } @PutMapping("/students/{id}") fun updateStudent( @@ -117,15 +117,16 @@ class AppController { @PathVariable id: UUID, @RequestBody body: StudentInput ) { - jdbi.inTransactionUnchecked { tx -> - tx.updateStudent(id = id, data = body, user = user) - }.also { - logger.audit( - user, - "UPDATE_STUDENT", - mapOf("studentId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.updateStudent(id = id, data = body, user = user) + }.also { + logger.audit( + user, + "UPDATE_STUDENT", + mapOf("studentId" to id.toString()) + ) + } } @DeleteMapping("/students/{id}") @@ -133,15 +134,16 @@ class AppController { user: AuthenticatedUser, @PathVariable id: UUID ) { - jdbi.inTransactionUnchecked { tx -> - tx.deleteStudent(id = id) - }.also { - logger.audit( - user, - "DELETE_STUDENT", - mapOf("studentId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.deleteStudent(id = id) + }.also { + logger.audit( + user, + "DELETE_STUDENT", + mapOf("studentId" to id.toString()) + ) + } } @PostMapping("/students/{studentId}/cases") @@ -149,17 +151,17 @@ class AppController { user: AuthenticatedUser, @PathVariable studentId: UUID, @RequestBody body: StudentCaseInput - ): UUID { - return jdbi.inTransactionUnchecked { tx -> - tx.insertStudentCase(studentId = studentId, data = body, user = user) - }.also { - logger.audit( - user, - "CREATE_STUDENT_CASE", - mapOf("studentId" to studentId.toString()) - ) - } - } + ): UUID = + jdbi + .inTransactionUnchecked { tx -> + tx.insertStudentCase(studentId = studentId, data = body, user = user) + }.also { + logger.audit( + user, + "CREATE_STUDENT_CASE", + mapOf("studentId" to studentId.toString()) + ) + } @PutMapping("/students/{studentId}/cases/{id}") fun updateStudentCase( @@ -168,15 +170,16 @@ class AppController { @PathVariable id: UUID, @RequestBody body: StudentCaseInput ) { - jdbi.inTransactionUnchecked { tx -> - tx.updateStudentCase(id = id, studentId = studentId, data = body, user = user) - }.also { - logger.audit( - user, - "UPDATE_STUDENT_CASE", - mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.updateStudentCase(id = id, studentId = studentId, data = body, user = user) + }.also { + logger.audit( + user, + "UPDATE_STUDENT_CASE", + mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) + ) + } } @DeleteMapping("/students/{studentId}/cases/{id}") @@ -185,15 +188,16 @@ class AppController { @PathVariable studentId: UUID, @PathVariable id: UUID ) { - jdbi.inTransactionUnchecked { tx -> - tx.deleteStudentCase(id = id, studentId = studentId) - }.also { - logger.audit( - user, - "DELETE_STUDENT_CASE", - mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.deleteStudentCase(id = id, studentId = studentId) + }.also { + logger.audit( + user, + "DELETE_STUDENT_CASE", + mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) + ) + } } @PutMapping("/students/{studentId}/cases/{id}/status") @@ -203,15 +207,16 @@ class AppController { @PathVariable id: UUID, @RequestBody body: CaseStatusInput ) { - jdbi.inTransactionUnchecked { tx -> - tx.updateStudentCaseStatus(id = id, studentId = studentId, data = body, user = user) - }.also { - logger.audit( - user, - "UPDATE_STUDENT_CASE_STATUS", - mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.updateStudentCaseStatus(id = id, studentId = studentId, data = body, user = user) + }.also { + logger.audit( + user, + "UPDATE_STUDENT_CASE_STATUS", + mapOf("studentId" to studentId.toString(), "caseId" to id.toString()) + ) + } } @PostMapping("/student-cases/{studentCaseId}/case-events") @@ -219,17 +224,17 @@ class AppController { user: AuthenticatedUser, @PathVariable studentCaseId: UUID, @RequestBody body: CaseEventInput - ): UUID { - return jdbi.inTransactionUnchecked { tx -> - tx.insertCaseEvent(studentCaseId = studentCaseId, data = body, user = user) - }.also { - logger.audit( - user, - "CREATE_CASE_EVENT", - mapOf("caseId" to studentCaseId.toString()) - ) - } - } + ): UUID = + jdbi + .inTransactionUnchecked { tx -> + tx.insertCaseEvent(studentCaseId = studentCaseId, data = body, user = user) + }.also { + logger.audit( + user, + "CREATE_CASE_EVENT", + mapOf("caseId" to studentCaseId.toString()) + ) + } @PutMapping("/case-events/{id}") fun updateCaseEvent( @@ -237,15 +242,16 @@ class AppController { @PathVariable id: UUID, @RequestBody body: CaseEventInput ) { - jdbi.inTransactionUnchecked { tx -> - tx.updateCaseEvent(id = id, data = body, user = user) - }.also { - logger.audit( - user, - "UPDATE_CASE_EVENT", - mapOf("eventId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.updateCaseEvent(id = id, data = body, user = user) + }.also { + logger.audit( + user, + "UPDATE_CASE_EVENT", + mapOf("eventId" to id.toString()) + ) + } } @DeleteMapping("/case-events/{id}") @@ -253,48 +259,46 @@ class AppController { user: AuthenticatedUser, @PathVariable id: UUID ) { - jdbi.inTransactionUnchecked { tx -> - tx.deleteCaseEvent(id = id) - }.also { - logger.audit( - user, - "DELETE_CASE_EVENT", - mapOf("eventId" to id.toString()) - ) - } + jdbi + .inTransactionUnchecked { tx -> + tx.deleteCaseEvent(id = id) + }.also { + logger.audit( + user, + "DELETE_CASE_EVENT", + mapOf("eventId" to id.toString()) + ) + } } @GetMapping("/employees") - fun getEmployeeUsers(user: AuthenticatedUser): List { - return jdbi.inTransactionUnchecked { it.getAppUsers() }.also { + fun getEmployeeUsers(user: AuthenticatedUser): List = + jdbi.inTransactionUnchecked { it.getAppUsers() }.also { logger.audit( user, "GET_EMPLOYEES" ) } - } @GetMapping("/reports/student-cases") fun getCasesReport( user: AuthenticatedUser, @RequestParam(required = false) start: LocalDate?, @RequestParam(required = false) end: LocalDate? - ): List { - return jdbi.inTransactionUnchecked { it.getCasesReport(CaseReportRequest(start, end)) }.also { + ): List = + jdbi.inTransactionUnchecked { it.getCasesReport(CaseReportRequest(start, end)) }.also { logger.audit( user, "GET_CASES_REPORT" ) } - } @DeleteMapping("/old-students") - fun deleteOldStudents(user: AuthenticatedUser) { - return jdbi.inTransactionUnchecked { it.deleteOldStudents() }.also { + fun deleteOldStudents(user: AuthenticatedUser) = + jdbi.inTransactionUnchecked { it.deleteOldStudents() }.also { logger.audit( user, "DELETE_OLD_STUDENTS" ) } - } } diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/CaseEvent.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/CaseEvent.kt index e612b9e4..ecac20dc 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/CaseEvent.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/CaseEvent.kt @@ -37,21 +37,19 @@ fun Handle.insertCaseEvent( studentCaseId: UUID, data: CaseEventInput, user: AuthenticatedUser -): UUID { - return createUpdate( +): UUID = + createUpdate( """ INSERT INTO case_events (created_by, student_case_id, date, type, notes) VALUES (:user, :studentCaseId, :date, :type, :notes) RETURNING id """ - ) - .bind("studentCaseId", studentCaseId) + ).bind("studentCaseId", studentCaseId) .bindKotlin(data) .bind("user", user.id) .executeAndReturnGeneratedKeys() .mapTo() .one() -} data class CaseEvent( val id: UUID, @@ -84,8 +82,7 @@ SET notes = :notes WHERE id = :id """ - ) - .bind("id", id) + ).bind("id", id) .bindKotlin(data) .bind("user", user.id) .execute() @@ -98,7 +95,6 @@ fun Handle.deleteCaseEvent(id: UUID) { DELETE FROM case_events WHERE id = :id """ - ) - .bind("id", id) + ).bind("id", id) .execute() } diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Reports.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Reports.kt index 2a8e26fa..c1f9a223 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Reports.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Reports.kt @@ -65,8 +65,7 @@ fun Handle.getCasesReport(request: CaseReportRequest): List = ${request.start?.let { "AND sc.opened_at >= :start" } ?: ""} ${request.end?.let { "AND sc.opened_at <= :end" } ?: ""} """ - ) - .also { if (request.start != null) it.bind("start", request.start) } + ).also { if (request.start != null) it.bind("start", request.start) } .also { if (request.end != null) it.bind("end", request.end) } .mapTo() .list() diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Student.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Student.kt index 82ef3cbe..8c054410 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Student.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/Student.kt @@ -43,20 +43,18 @@ data class StudentInput( fun Handle.insertStudent( data: StudentInput, user: AuthenticatedUser -): UUID { - return createUpdate( +): UUID = + createUpdate( """ INSERT INTO students (created_by, valpas_link, ssn, first_name, last_name, language, date_of_birth, phone, email, gender, address, municipality_in_finland, guardian_info, support_contacts_info) VALUES (:user, :valpasLink, :ssn, :firstName, :lastName, :language, :dateOfBirth, :phone, :email, :gender, :address, :municipalityInFinland, :guardianInfo, :supportContactsInfo) RETURNING id """ - ) - .bindKotlin(data) + ).bindKotlin(data) .bind("user", user.id) .executeAndReturnGeneratedKeys() .mapTo() .one() -} data class StudentSummary( val id: UUID, @@ -132,8 +130,7 @@ ${if (params.query != null) { }} ORDER BY opened_at DESC NULLS LAST, last_name, first_name """ - ) - .bind("query", params.query?.trim()?.lowercase()) + ).bind("query", params.query?.trim()?.lowercase()) .bind("statuses", params.statuses.toTypedArray()) .bind("sources", params.sources.toTypedArray()) .bind("assignedTo", params.assignee?.assignedTo) @@ -180,8 +177,7 @@ SELECT id, valpas_link, ssn, first_name, last_name, language, date_of_birth, pho FROM students WHERE id = :id """ - ) - .bind("id", id) + ).bind("id", id) .mapTo() .findOne() .getOrNull() @@ -213,8 +209,7 @@ SET support_contacts_info = :supportContactsInfo WHERE id = :id """ - ) - .bind("id", id) + ).bind("id", id) .bindKotlin(data) .bind("user", user.id) .execute() @@ -251,8 +246,9 @@ fun Handle.getPossibleDuplicateStudents(input: DuplicateStudentCheckInput): List lower(first_name) = lower(:firstName) AND lower(last_name) = lower(:lastName) AND (ssn = '' OR :ssn = '') - )""" - .takeIf { input.firstName.isNotBlank() && input.lastName.isNotBlank() } + )""".takeIf { + input.firstName.isNotBlank() && input.lastName.isNotBlank() + } return createQuery( """ @@ -269,8 +265,7 @@ fun Handle.getPossibleDuplicateStudents(input: DuplicateStudentCheckInput): List SELECT * FROM match_data WHERE matching_ssn OR matching_valpas_link OR matching_name """ - ) - .configure(SqlStatements::class.java) { it.setUnusedBindingAllowed(true) } + ).configure(SqlStatements::class.java) { it.setUnusedBindingAllowed(true) } .bindKotlin(input) .mapTo() .list() @@ -306,7 +301,6 @@ fun Handle.deleteOldStudents() { DELETE FROM students WHERE id IN (SELECT id FROM students_to_delete) """ - ) - .bind("threshold", LocalDate.now().minusYears(21)) + ).bind("threshold", LocalDate.now().minusYears(21)) .execute() } diff --git a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/StudentCase.kt b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/StudentCase.kt index 102da71f..a041fc80 100644 --- a/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/StudentCase.kt +++ b/service/src/main/kotlin/fi/espoo/oppivelvollisuus/domain/StudentCase.kt @@ -117,21 +117,19 @@ fun Handle.insertStudentCase( studentId: UUID, data: StudentCaseInput, user: AuthenticatedUser -): UUID { - return createUpdate( +): UUID = + createUpdate( """ INSERT INTO student_cases (created_by, student_id, opened_at, assigned_to, status, source, source_valpas, source_other, source_contact, school_background, case_background_reasons, not_in_school_reason) VALUES (:user, :studentId, :openedAt, :assignedTo, 'TODO', :source, :sourceValpas, :sourceOther, :sourceContact, :schoolBackground::school_background[], :caseBackgroundReasons::case_background_reason[], :notInSchoolReason) RETURNING id """ - ) - .bind("studentId", studentId) + ).bind("studentId", studentId) .bindKotlin(data) .bind("user", user.id) .executeAndReturnGeneratedKeys() .mapTo() .one() -} enum class CaseFinishedReason { BEGAN_STUDIES, @@ -241,8 +239,7 @@ LEFT JOIN users assignee ON sc.assigned_to = assignee.id WHERE student_id = :studentId ORDER BY opened_at DESC, sc.created DESC; """ - ) - .bind("studentId", studentId) + ).bind("studentId", studentId) .mapTo() .list() @@ -269,8 +266,7 @@ SET not_in_school_reason = :notInSchoolReason WHERE id = :id AND student_id = :studentId """ - ) - .bind("id", id) + ).bind("id", id) .bind("studentId", studentId) .bindKotlin(data) .bind("user", user.id) @@ -306,8 +302,7 @@ SET started_at_school = :startedAtSchool WHERE id = :id AND student_id = :studentId """ - ) - .bind("id", id) + ).bind("id", id) .bind("studentId", studentId) .bind("status", data.status) .bind("finishedReason", data.finishedInfo?.reason) diff --git a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CaseEvenTests.kt b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CaseEvenTests.kt index 6f6be79f..8fea2b5a 100644 --- a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CaseEvenTests.kt +++ b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CaseEvenTests.kt @@ -23,9 +23,19 @@ class CaseEvenTests : FullApplicationTest() { @Test fun `create new case event, then update it and finally delete it`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id - var events = controller.getStudent(testUser, studentId).cases.first().events + var events = + controller + .getStudent(testUser, studentId) + .cases + .first() + .events assertEquals(emptyList(), events) val eventId = @@ -39,7 +49,12 @@ class CaseEvenTests : FullApplicationTest() { ) ) - events = controller.getStudent(testUser, studentId).cases.first().events + events = + controller + .getStudent(testUser, studentId) + .cases + .first() + .events assertEquals(1, events.size) events.first().let { event -> assertEquals(eventId, event.id) @@ -60,7 +75,12 @@ class CaseEvenTests : FullApplicationTest() { ) ) - events = controller.getStudent(testUser, studentId).cases.first().events + events = + controller + .getStudent(testUser, studentId) + .cases + .first() + .events assertEquals(1, events.size) events.first().let { event -> assertEquals(eventId, event.id) @@ -73,7 +93,12 @@ class CaseEvenTests : FullApplicationTest() { controller.deleteCaseEvent(testUser, eventId) - events = controller.getStudent(testUser, studentId).cases.first().events + events = + controller + .getStudent(testUser, studentId) + .cases + .first() + .events assertEquals(0, events.size) } } diff --git a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CasesReportTests.kt b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CasesReportTests.kt index c3fd2ac9..21201606 100644 --- a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CasesReportTests.kt +++ b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/CasesReportTests.kt @@ -68,7 +68,12 @@ class CasesReportTests : FullApplicationTest() { ) ) ) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id assertEquals( listOf( diff --git a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/FullApplicationTest.kt b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/FullApplicationTest.kt index 5dc72cb9..809e1f66 100644 --- a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/FullApplicationTest.kt +++ b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/FullApplicationTest.kt @@ -50,12 +50,14 @@ abstract class FullApplicationTest { fun beforeEach() { jdbi.withHandleUnchecked { tx -> tx.execute("SELECT reset_database()") - tx.createUpdate( - """ + tx + .createUpdate( + """ INSERT INTO users (id, updated, external_id, first_names, last_name, email) VALUES (:id, now(), 'test', 'Teija', 'Testaaja', NULL) """ - ).bind("id", testUser.id).execute() + ).bind("id", testUser.id) + .execute() } } } diff --git a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentCaseTests.kt b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentCaseTests.kt index df181e1b..0f4d965e 100644 --- a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentCaseTests.kt +++ b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentCaseTests.kt @@ -207,7 +207,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `change status to ON_HOLD`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.updateStudentCaseStatus(testUser, studentId, caseId, CaseStatusInput(CaseStatus.ON_HOLD, null)) @@ -219,7 +224,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `change status to FINISHED`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.updateStudentCaseStatus( testUser, @@ -237,7 +247,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `change status to FINISHED with BEGAN_STUDIES`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.updateStudentCaseStatus( testUser, @@ -258,7 +273,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `cannot change status to FINISHED without reason`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id assertThrows { controller.updateStudentCaseStatus( @@ -276,7 +296,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `cannot change status to FINISHED with BEGAN_STUDIES without school type`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id assertThrows { controller.updateStudentCaseStatus( @@ -297,7 +322,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `cannot provide startedAtSchool when reason is not BEGAN_STUDIES`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id assertThrows { controller.updateStudentCaseStatus( @@ -318,7 +348,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `reset status after finishing`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.updateStudentCaseStatus( testUser, studentId, @@ -341,7 +376,12 @@ class StudentCaseTests : FullApplicationTest() { @Test fun `cannot reset status after finishing if there already is another unfinished case`() { val studentId = controller.createStudent(testUser, minimalStudentAndCaseTestInput) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.updateStudentCaseStatus( testUser, studentId, @@ -367,7 +407,12 @@ class StudentCaseTests : FullApplicationTest() { user = testUser, body = minimalStudentAndCaseTestInput ) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.deleteStudentCase(testUser, studentId, caseId) @@ -404,7 +449,12 @@ class StudentCaseTests : FullApplicationTest() { user = testUser, body = minimalStudentAndCaseTestInput ) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.createCaseEvent( testUser, caseId, diff --git a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentTests.kt b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentTests.kt index 2fd375b1..e053899b 100644 --- a/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentTests.kt +++ b/service/src/test/kotlin/fi/espoo/oppivelvollisuus/StudentTests.kt @@ -93,7 +93,12 @@ class StudentTests : FullApplicationTest() { ) ) ) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.createCaseEvent( testUser, caseId, @@ -559,7 +564,12 @@ class StudentTests : FullApplicationTest() { user = testUser, body = minimalStudentAndCaseTestInput ) - val caseId = controller.getStudent(testUser, studentId).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId) + .cases + .first() + .id controller.deleteStudentCase(testUser, studentId, caseId) controller.deleteStudent(testUser, studentId) @@ -594,7 +604,12 @@ class StudentTests : FullApplicationTest() { studentCase = minimalStudentCaseTestInput ) ) - val caseId = controller.getStudent(testUser, studentId1).cases.first().id + val caseId = + controller + .getStudent(testUser, studentId1) + .cases + .first() + .id controller.createCaseEvent(testUser, caseId, CaseEventInput(LocalDate.now(), CaseEventType.NOTE, "foo")) controller.deleteOldStudents(testUser)