diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/ClassManager.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/ClassManager.kt
index 9bfe3b83..19949b9d 100644
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/ClassManager.kt
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/ClassManager.kt
@@ -70,4 +70,12 @@ interface ClassManager {
* @param clazz the class to save
*/
fun saveClass(clazz: Clazz)
+
+ /**
+ * A pending participation means, if any participant of the given {@code clazz}
+ * as no sport.
+ *
+ * @return true if the class has pending participation, otherwise false
+ */
+ fun hasPendingParticipation(clazz: Clazz): Boolean
}
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManager.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManager.kt
index f1f8fe0a..a9ee0e4d 100644
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManager.kt
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManager.kt
@@ -90,12 +90,17 @@ class DefaultClassManager(
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
- private fun ClazzEntity.pendingParticipation() = competitorRepository.findByClazzName(this.name).any { it.sport == null }
+ /**
+ * A pending participation means, if any participant of the given {@code clazz}
+ * as no sport.
+ *
+ * @return true if the class has pending participation, otherwise false
+ */
+ override fun hasPendingParticipation(clazz: Clazz) = competitorRepository.findByClazzName(clazz.name).any { it.sport == null }
private fun ClazzEntity.map(): Clazz {
return Clazz(
name,
- Coach(coach.id!!, coach.name),
- pendingParticipation())
+ Coach(coach.id!!, coach.name))
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/RestModels.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/RestModels.kt
new file mode 100644
index 00000000..15761bd4
--- /dev/null
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/RestModels.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018 by Nicolas Märchy
+ *
+ * This file is part of Sporttag PSA.
+ *
+ * Sporttag PSA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Sporttag PSA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Sporttag PSA. If not, see .
+ *
+ * Diese Datei ist Teil von Sporttag PSA.
+ *
+ * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen
+ * der GNU General Public License, wie von der Free Software Foundation,
+ * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren
+ * veröffentlichten Version, weiterverbreiten und/oder modifizieren.
+ *
+ * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber
+ * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
+ * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ * Siehe die GNU General Public License für weitere Details.
+ *
+ * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
+ * Programm erhalten haben. Wenn nicht, siehe .
+ *
+ *
+ */
+
+package ch.schulealtendorf.sporttagpsa.controller.rest
+
+import javax.validation.constraints.NotNull
+
+/*
+ * Because POJOs for Spring Rest Controller needs to have a default parameter
+ * and we can validate our POJOs with Spring Annotations, we make every property nullable
+ * and initialize it with null (like in Java where null-safe does not exist).
+ *
+ * If a property is required we annotate it with @NotNull, in order to validate it with Spring.
+ */
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+data class RestClass(
+
+ @NotNull
+ var name: String? = null,
+
+ @NotNull
+ var coach: String? = null,
+
+ @NotNull
+ var pendingParticipation: Boolean? = null
+)
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+data class RestTown(
+
+ @NotNull
+ var id: Int? = null,
+
+ @NotNull
+ var zip: String? = null,
+
+ @NotNull
+ var name: String? = null
+)
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+data class RestParticipant(
+
+ @NotNull
+ var id: Int? = null,
+
+ @NotNull
+ var surname: String? = null,
+
+ @NotNull
+ var prename: String? = null,
+
+ @NotNull
+ var gender: Boolean? = null,
+
+ @NotNull
+ var birthday: Long? = null,
+
+ @NotNull
+ var absent: Boolean? = null,
+
+ @NotNull
+ var address: String? = null,
+
+ @NotNull
+ var town: RestTown? = null,
+
+ @NotNull
+ var clazz: RestClass? = null,
+
+ @NotNull
+ var sport: String? = null
+)
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+data class RestPutParticipant(
+
+ @NotNull
+ var surname: String? = null,
+
+ @NotNull
+ var prename: String? = null,
+
+ @NotNull
+ var gender: Boolean? = null,
+
+ @NotNull
+ var birthday: Long? = null,
+
+ @NotNull
+ var address: String? = null,
+
+ @NotNull
+ var absent: Boolean? = null
+)
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+data class RestPatchParticipant(
+ var town: RestTown? = null,
+ var clazz: RestClass? = null,
+ var sport: String? = null
+)
\ No newline at end of file
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/clazz/ClassController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/clazz/ClassController.kt
index b53a4027..e61f4d95 100644
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/clazz/ClassController.kt
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/clazz/ClassController.kt
@@ -38,6 +38,7 @@ package ch.schulealtendorf.sporttagpsa.controller.rest.clazz
import ch.schulealtendorf.sporttagpsa.business.clazz.ClassManager
import ch.schulealtendorf.sporttagpsa.controller.rest.BadRequestException
+import ch.schulealtendorf.sporttagpsa.controller.rest.RestClass
import ch.schulealtendorf.sporttagpsa.model.Clazz
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.GetMapping
@@ -56,12 +57,24 @@ class ClassController(
) {
@GetMapping("/classes", produces = [MediaType.APPLICATION_JSON_VALUE])
- fun getAllClasses() = classManager.getAllClasses()
+ fun getAllClasses(): List {
+ return classManager.getAllClasses()
+ .map { it.map() }
+ }
@GetMapping("/class/{class_id}", produces = [MediaType.APPLICATION_JSON_VALUE])
- fun getClass(@PathVariable("class_id") classId: String): Clazz {
+ fun getClass(@PathVariable("class_id") classId: String): RestClass {
+
+ val clazz = classManager.getClass(classId).orElseThrow { BadRequestException("Could not find class with id '$classId'") }
+
+ return clazz.map()
+ }
- val clazz = classManager.getClass(classId)
- return clazz.orElseThrow { BadRequestException("Could not find class with id '$classId'") }
+ private fun Clazz.map(): RestClass {
+ return RestClass(
+ name,
+ coach.name,
+ classManager.hasPendingParticipation(this)
+ )
}
}
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt
index da0bf853..b6af559d 100644
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantController.kt
@@ -36,16 +36,154 @@
package ch.schulealtendorf.sporttagpsa.controller.rest.participant
-import org.springframework.web.bind.annotation.RestController
+import ch.schulealtendorf.sporttagpsa.business.clazz.ClassManager
+import ch.schulealtendorf.sporttagpsa.business.participant.ParticipantManager
+import ch.schulealtendorf.sporttagpsa.controller.rest.*
+import ch.schulealtendorf.sporttagpsa.model.*
+import org.springframework.http.MediaType
+import org.springframework.web.bind.annotation.*
+import javax.validation.Valid
/**
+ * Rest controller for the participants.
+ *
* @author nmaerchy
* @since 2.0.0
*/
@RestController
-class ParticipantController() {
+class ParticipantController(
+ private val participantManager: ParticipantManager,
+ private val classManager: ClassManager
+) {
+
+ @GetMapping("/participants", produces = [MediaType.APPLICATION_JSON_VALUE])
+ fun getAllParticipants(@RequestParam("class", required = false) clazzName: String?): List {
+
+ if (clazzName == null) {
+ return participantManager.getAllParticipants().map { it.map() }
+ }
+
+ val clazz = classManager.getClass(clazzName).orElseThrow { BadRequestException("Could not find class with name '$clazzName'") }
+
+ return participantManager.getAllParticipants(clazz).map { it.map() }
+ }
+
+ @PostMapping("/participant")
+ fun addParticipant() {
+ TODO("This request is not supported yet")
+ }
+
+ @GetMapping("/participant/{participant_id}")
+ fun getParticipant(@PathVariable("participant_id") participantId: Int): RestParticipant {
+
+ return participantManager.getParticipant(participantId)
+ .map { it.map() }
+ .orElseThrow { BadRequestException("Could not find participant with id '$participantId'") }
+ }
+
+ @PutMapping("/participant/{participant_id}")
+ fun updateParticipant(@PathVariable("participant_id") participantId: Int, @Valid @RequestBody restParticipant: RestPutParticipant) {
+
+ val participant = participantManager.getParticipant(participantId)
+ .orElseThrow { BadRequestException("Could not find participant with id '$participantId'") }
+
+ val updatedParticipant = participant.copy(
+ surname = restParticipant.surname!!,
+ prename = restParticipant.prename!!,
+ gender = Gender(restParticipant.absent!!),
+ birthday = Birthday(restParticipant.birthday!!),
+ address = restParticipant.address!!,
+ absent = restParticipant.absent!!
+ )
+
+ participantManager.saveParticipant(updatedParticipant)
+ }
+
+ @PatchMapping("/participant/{participant_id}")
+ fun updateParticipant(@PathVariable("participant_id") participantId: Int, @Valid @RequestBody restParticipant: RestPatchParticipant) {
+
+ if (restParticipant.clazz == null && restParticipant.town == null && restParticipant.sport == null) {
+ throw BadRequestException("Missing either 'clazz', 'town' or 'sport' in request body.")
+ }
+
+ val participant = participantManager.getParticipant(participantId)
+ .orElseThrow { BadRequestException("Could not find participant with id '$participantId'") }
+
+ if (restParticipant.clazz != null) {
+ val clazz = classManager.getClass(restParticipant.clazz!!.name!!)
+ .orElseThrow { BadRequestException("Could not find class with name''${restParticipant.clazz!!.name}") }
+ participant.update(clazz)
+ }
+
+ if (restParticipant.sport != null) {
+ participant.update(restParticipant.sport!!)
+ }
+
+ if (restParticipant.town != null) {
+ participant.update(restParticipant.town!!)
+ }
+ }
+
+ private fun Participant.update(sport: String) {
+ participantManager.saveParticipant(
+ this.copy(
+ sport = java.util.Optional.of(sport)
+ )
+ )
+ }
+
+ private fun Participant.update(town: RestTown) {
+ participantManager.saveParticipant(
+ this.copy(
+ town = town.map()
+ )
+ )
+ }
+
+ private fun Participant.update(clazz: Clazz) {
+ participantManager.saveParticipant(
+ this.copy(
+ clazz = clazz
+ )
+ )
+ }
+
+ private fun Participant.map(): RestParticipant {
+ return RestParticipant(
+ id,
+ surname,
+ prename,
+ gender.value,
+ birthday.milliseconds,
+ absent,
+ address,
+ town.map(),
+ clazz.map(),
+ sport.orElse(null)
+ )
+ }
+
+ private fun Clazz.map(): RestClass {
+ return RestClass(
+ name,
+ coach.name,
+ classManager.hasPendingParticipation(this)
+ )
+ }
+
+ private fun Town.map(): RestTown {
+ return RestTown(
+ id,
+ zip,
+ name
+ )
+ }
- fun getAllParticipants(): List {
- TODO("not implemented yet")
+ private fun RestTown.map(): Town {
+ return Town(
+ id!!,
+ zip!!,
+ name!!
+ )
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/RestModels.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/RestModels.kt
deleted file mode 100644
index 6cb6907a..00000000
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/RestModels.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2018 by Nicolas Märchy
- *
- * This file is part of Sporttag PSA.
- *
- * Sporttag PSA is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Sporttag PSA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Sporttag PSA. If not, see .
- *
- * Diese Datei ist Teil von Sporttag PSA.
- *
- * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen
- * der GNU General Public License, wie von der Free Software Foundation,
- * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren
- * veröffentlichten Version, weiterverbreiten und/oder modifizieren.
- *
- * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber
- * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
- * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
- * Siehe die GNU General Public License für weitere Details.
- *
- * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
- * Programm erhalten haben. Wenn nicht, siehe .
- *
- *
- */
-
-package ch.schulealtendorf.sporttagpsa.controller.rest.participant
-
-import ch.schulealtendorf.sporttagpsa.model.Clazz
-import ch.schulealtendorf.sporttagpsa.model.Town
-
-/**
- * Data class representing a participant used in rest requests.
- *
- * @author nmaerchy
- * @since 2.0.0
- */
-data class RestParticipant(
- val id: Int,
- val surname: String,
- val prename: String,
- val gender: Boolean,
- val birthday: Long,
- val absent: Boolean,
- val address: String,
- val town: Town,
- val clazz: Clazz,
- val sport: String
-)
diff --git a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/model/Clazz.kt b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/model/Clazz.kt
index a37a1713..cc5c983b 100644
--- a/src/main/kotlin/ch/schulealtendorf/sporttagpsa/model/Clazz.kt
+++ b/src/main/kotlin/ch/schulealtendorf/sporttagpsa/model/Clazz.kt
@@ -42,8 +42,7 @@ package ch.schulealtendorf.sporttagpsa.model
* @author nmaerchy
* @since 2.0.0
*/
-data class Clazz @JvmOverloads constructor(
+data class Clazz(
val name: String,
- val coach: Coach,
- val pendingParticipation: Boolean = false
+ val coach: Coach
)
diff --git a/src/test/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManagerSpec.kt b/src/test/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManagerSpec.kt
index 176da9f1..5c02ee6e 100644
--- a/src/test/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManagerSpec.kt
+++ b/src/test/kotlin/ch/schulealtendorf/sporttagpsa/business/clazz/DefaultClassManagerSpec.kt
@@ -36,7 +36,8 @@
package ch.schulealtendorf.sporttagpsa.business.clazz
-import ch.schulealtendorf.sporttagpsa.entity.*
+import ch.schulealtendorf.sporttagpsa.entity.CompetitorEntity
+import ch.schulealtendorf.sporttagpsa.entity.SportEntity
import ch.schulealtendorf.sporttagpsa.model.Clazz
import ch.schulealtendorf.sporttagpsa.model.Coach
import ch.schulealtendorf.sporttagpsa.repository.ClazzRepository
@@ -46,8 +47,12 @@ import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.reset
import com.nhaarman.mockito_kotlin.whenever
import org.jetbrains.spek.api.Spek
-import org.jetbrains.spek.api.dsl.*
-import kotlin.test.assertEquals
+import org.jetbrains.spek.api.dsl.context
+import org.jetbrains.spek.api.dsl.describe
+import org.jetbrains.spek.api.dsl.it
+import org.jetbrains.spek.api.dsl.on
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
/**
* @author nmaerchy
@@ -65,17 +70,12 @@ object DefaultClassManagerSpec: Spek({
val running = SportEntity("Running")
- val classes: List = listOf(
- ClazzEntity("2a", CoachEntity(1, "Max Muster")),
- ClazzEntity("2b", CoachEntity(2, "Max Master")),
- ClazzEntity("2c", CoachEntity(3, "Max Mister"))
- )
beforeEachTest {
reset(mockClassRepository, mockClassRepository)
}
- context("get all classes") {
+ context("has pending participation") {
on("no pending participation") {
@@ -86,21 +86,15 @@ object DefaultClassManagerSpec: Spek({
CompetitorEntity().apply { sport = running }
)
- whenever(mockClassRepository.findAll()).thenReturn(classes)
whenever(mockCompetitorRepository.findByClazzName(any())).thenReturn(competitors)
- val result = classManager.getAllClasses()
+ val clazz = Clazz("2a", Coach(1, "Müller"))
+ val result = classManager.hasPendingParticipation(clazz)
- it("should return a list of classes with no pending participation") {
-
- val expected: List = listOf(
- Clazz("2a", Coach(1, "Max Muster")),
- Clazz("2b", Coach(2, "Max Master")),
- Clazz("2c", Coach(3, "Max Mister"))
- )
- assertEquals(expected, result)
+ it("should return false") {
+ assertFalse(result)
}
}
@@ -113,21 +107,15 @@ object DefaultClassManagerSpec: Spek({
CompetitorEntity() // one competitor has no sport so the class has pending participation
)
- whenever(mockClassRepository.findAll()).thenReturn(classes)
whenever(mockCompetitorRepository.findByClazzName(any())).thenReturn(competitors)
- val result = classManager.getAllClasses()
+ val clazz = Clazz("2a", Coach(1, "Müller"))
+ val result = classManager.hasPendingParticipation(clazz)
it("should return a list of classes with pending participation") {
-
- val expected: List = listOf(
- Clazz("2a", Coach(1, "Max Muster"), true),
- Clazz("2b", Coach(2,"Max Master"), true),
- Clazz("2c", Coach(3, "Max Mister"), true)
- )
- assertEquals(expected, result)
+ assertTrue(result)
}
}
}
diff --git a/src/test/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantControllerSpec.kt b/src/test/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantControllerSpec.kt
new file mode 100644
index 00000000..206ef133
--- /dev/null
+++ b/src/test/kotlin/ch/schulealtendorf/sporttagpsa/controller/rest/participant/ParticipantControllerSpec.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2018 by Nicolas Märchy
+ *
+ * This file is part of Sporttag PSA.
+ *
+ * Sporttag PSA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Sporttag PSA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Sporttag PSA. If not, see .
+ *
+ * Diese Datei ist Teil von Sporttag PSA.
+ *
+ * Sporttag PSA ist Freie Software: Sie können es unter den Bedingungen
+ * der GNU General Public License, wie von der Free Software Foundation,
+ * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren
+ * veröffentlichten Version, weiterverbreiten und/oder modifizieren.
+ *
+ * Sporttag PSA wird in der Hoffnung, dass es nützlich sein wird, aber
+ * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
+ * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
+ * Siehe die GNU General Public License für weitere Details.
+ *
+ * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
+ * Programm erhalten haben. Wenn nicht, siehe .
+ *
+ *
+ */
+
+package ch.schulealtendorf.sporttagpsa.controller.rest.participant
+
+import ch.schulealtendorf.sporttagpsa.business.clazz.ClassManager
+import ch.schulealtendorf.sporttagpsa.business.participant.ParticipantManager
+import ch.schulealtendorf.sporttagpsa.controller.rest.BadRequestException
+import ch.schulealtendorf.sporttagpsa.controller.rest.RestClass
+import ch.schulealtendorf.sporttagpsa.controller.rest.RestPatchParticipant
+import ch.schulealtendorf.sporttagpsa.controller.rest.RestTown
+import ch.schulealtendorf.sporttagpsa.model.*
+import com.nhaarman.mockito_kotlin.*
+import org.jetbrains.spek.api.Spek
+import org.jetbrains.spek.api.dsl.context
+import org.jetbrains.spek.api.dsl.describe
+import org.jetbrains.spek.api.dsl.it
+import org.jetbrains.spek.api.dsl.on
+import java.util.*
+import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
+
+/**
+ * @author nmaerchy
+ * @since 2.0.0
+ */
+object ParticipantControllerSpec: Spek({
+
+ describe("a participant rest controller") {
+
+ val mockParticipantManager: ParticipantManager = mock()
+ val mockClassManager: ClassManager = mock()
+
+ val controller = ParticipantController(mockParticipantManager, mockClassManager)
+
+
+ val participant = Participant(
+ 1,
+ "Muster",
+ "Max",
+ Gender.male(),
+ Birthday(0),
+ false,
+ "",
+ Town(1, "3000", "Bern"),
+ Clazz("2a", Coach(1, "Müller"))
+ )
+
+ beforeEachTest {
+ reset(mockParticipantManager, mockClassManager)
+ }
+
+ context("patch a participant") {
+
+ on("given town to update") {
+
+ whenever(mockParticipantManager.getParticipant(any())).thenReturn(Optional.of(participant))
+
+
+ val town = RestTown(2, "8000", "Zürich")
+ val patchParticipant = RestPatchParticipant(town)
+ controller.updateParticipant(1, patchParticipant)
+
+
+ it("should update the town of the participant") {
+ val expected = participant.copy(
+ town = Town(2, "8000", "Zürich")
+ )
+ verify(mockParticipantManager, times(1)).saveParticipant(expected)
+ }
+ }
+
+ on("given class to update") {
+
+ whenever(mockParticipantManager.getParticipant(any())).thenReturn(Optional.of(participant))
+
+ val clazz = Clazz("3a", Coach(2, "Muster"))
+ whenever(mockClassManager.getClass(any())).thenReturn(Optional.of(clazz))
+
+
+ val restClass = RestClass("3a", "Muster", false)
+ val patchParticipant = RestPatchParticipant(clazz = restClass)
+ controller.updateParticipant(1, patchParticipant)
+
+
+ it("should update the class of the participant") {
+ val expected = participant.copy(
+ clazz = clazz
+ )
+ verify(mockParticipantManager, times(1)).saveParticipant(expected)
+ }
+ }
+
+ on("given sport to update") {
+
+ whenever(mockParticipantManager.getParticipant(any())).thenReturn(Optional.of(participant))
+
+ val patchParticipant = RestPatchParticipant(sport = "Running")
+ controller.updateParticipant(1, patchParticipant)
+
+
+ it("should update the sport of the participant") {
+ val expected = participant.copy(
+ sport = Optional.of("Running")
+ )
+ verify(mockParticipantManager, times(1)).saveParticipant(expected)
+ }
+ }
+
+ on("nothing is given") {
+
+ it("should throw a bad request exception") {
+ val exception = assertFailsWith {
+ controller.updateParticipant(1, RestPatchParticipant())
+ }
+ assertEquals("Missing either 'clazz', 'town' or 'sport' in request body.", exception.message)
+ }
+ }
+ }
+ }
+})