Split controller for better maintainability

This commit is contained in:
neviyn 2019-02-18 10:45:15 +00:00
parent 742faa7bf3
commit 9e86e1a593
5 changed files with 168 additions and 108 deletions

View File

@ -62,6 +62,18 @@ data class ChartDataset(
constructor(label: String, color: String, data: List<Double>) : this(label, color, color, data) constructor(label: String, color: String, data: List<Double>) : this(label, color, color, data)
} }
data class AverageData(
val monitoring: Double,
val controlProcedural: Double,
val control: Double,
val conservatism: Double,
val teamworkCommunications: Double,
val teamworkLeadership: Double,
val teamworkWorkload: Double,
val knowledge: Double,
val date: LocalDate
)
data class AfiPieChart( data class AfiPieChart(
val labels: List<String> = listOf("Monitoring", "Knowledge", "Control", "Conservatism", "Teamwork"), val labels: List<String> = listOf("Monitoring", "Knowledge", "Control", "Conservatism", "Teamwork"),
val datasets: List<AfiPieChartDataset> val datasets: List<AfiPieChartDataset>

View File

@ -0,0 +1,120 @@
package uk.co.neviyn.observationdatabase.controller
import org.joda.time.LocalDate
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.core.env.Environment
import org.springframework.core.env.get
import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import uk.co.neviyn.observationdatabase.GroupObservation
import uk.co.neviyn.observationdatabase.GroupObservationInit
import uk.co.neviyn.observationdatabase.GroupSessionManager
import uk.co.neviyn.observationdatabase.Observation
import uk.co.neviyn.observationdatabase.Person
import uk.co.neviyn.observationdatabase.PersonRepository
import uk.co.neviyn.observationdatabase.SiteRepository
import uk.co.neviyn.observationdatabase.TutorRepository
import java.net.Inet4Address
import java.net.NetworkInterface
@RestController
@RequestMapping("/api/grpob")
@CrossOrigin
class GroupSessionController {
private val logger: Logger = LoggerFactory.getLogger(javaClass)!!
@Autowired
lateinit var environment: Environment
@Autowired
lateinit var siteRepository: SiteRepository
@Autowired
lateinit var tutorRepository: TutorRepository
@Autowired
lateinit var observationsController: ObservationsController
@Autowired
lateinit var personRepository: PersonRepository
@PostMapping("/start")
fun startGroupObservation(initData: GroupObservationInit): Map<String, String> {
val site = siteRepository.findById(initData.site)
val tutors = tutorRepository.findAllById(initData.tutors).toSet()
if (!site.isPresent) {
logger.info("Attempted to add Observation without a site.")
return mapOf("error" to "Site required")
}
if (tutors.isEmpty() || tutors.size != initData.tutors.size) {
logger.info("Attempted to add Observation without a tutor")
return mapOf("error" to "Tutor(s) required")
}
val sessionId = GroupSessionManager.startNewSession(site.get(), tutors, initData.type, initData.scenarioTitles)
return getConnectionDetails().plus("id" to sessionId.toString())
}
@GetMapping("/recover")
fun reconnectToGroupObservation(): Map<String, Any> {
logger.debug("Previous group observation requested")
return getConnectionDetails().plus(mapOf("id" to GroupSessionManager.sessionId.toString(), "observations" to GroupSessionManager.observations))
}
@GetMapping("/valid/{id}")
fun checkGroupObservationValidityById(@PathVariable id: Int): Map<String, Any> {
if (GroupSessionManager.isValid(id)) {
return mapOf("titles" to GroupSessionManager.scenarioTitles!!)
}
logger.warn("Group observation requested with id $id but there is no valid session")
return mapOf("error" to "no valid session")
}
@GetMapping("/valid")
fun checkGroupObservationValidity(): Boolean {
return GroupSessionManager.isValid()
}
@PostMapping("/submit")
fun addGroupObservation(observationData: GroupObservation) {
if (GroupSessionManager.isValid()) {
var observation = Observation(
site = GroupSessionManager.site!!,
date = LocalDate.now(),
type = GroupSessionManager.trainingType!!,
observed = observationData.scenarios.joinToString { it.title },
monitoring = observationData.scenarios.map { it.monitoring.rating }.average(),
conservatism = observationData.scenarios.map { it.conservatism.rating }.average(),
controlProcedural = observationData.scenarios.map { it.controlProcedural.rating }.average(),
control = observationData.scenarios.map { it.control.rating }.average(),
teamworkCommunications = observationData.scenarios.map { it.teamworkCommunications.rating }.average(),
teamworkLeadership = observationData.scenarios.map { it.teamworkLeadership.rating }.average(),
teamworkWorkload = observationData.scenarios.map { it.teamworkWorkload.rating }.average(),
knowledge = observationData.scenarios.map { it.knowledge.rating }.average(),
scenarios = observationData.scenarios,
tutors = GroupSessionManager.tutors!!,
person = personRepository.findFirstByNameLike(observationData.person.toUpperCase()) ?: personRepository.save(Person(name = observationData.person.toUpperCase()))
)
observation = observationsController.saveObservation(observation)
GroupSessionManager.addObservation(observation)
}
}
@GetMapping("/address")
fun getConnectionDetails(): Map<String, String> {
var ipv4: String? = null
var retryCount = 0
while (ipv4 == null && retryCount < 3) {
ipv4 = NetworkInterface.getNetworkInterfaces().asSequence()
.filter { !it.isLoopback }.map { x -> x.inetAddresses.asSequence()
.filter { it is Inet4Address }.map { it.hostAddress } }.flatten().firstOrNull()
retryCount++
Thread.sleep(1_000) // Sleep for 1 second
}
if (ipv4 != null)
return mapOf("ip" to ipv4, "port" to environment["local.server.port"])
return mapOf("error" to "Could not determine IP Address")
}
}

View File

@ -1,33 +1,44 @@
package uk.co.neviyn.observationdatabase package uk.co.neviyn.observationdatabase.controller
import org.joda.time.LocalDate import org.joda.time.LocalDate
import org.slf4j.Logger import org.slf4j.Logger
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cache.annotation.Cacheable import org.springframework.cache.annotation.Cacheable
import org.springframework.core.env.Environment import org.springframework.web.bind.annotation.CrossOrigin
import org.springframework.core.env.get
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.CrossOrigin import uk.co.neviyn.observationdatabase.AfiPieChart
import java.net.Inet4Address import uk.co.neviyn.observationdatabase.AfiPieChartDataset
import java.net.NetworkInterface import uk.co.neviyn.observationdatabase.AverageData
import uk.co.neviyn.observationdatabase.ChartData
import uk.co.neviyn.observationdatabase.ChartDataset
import uk.co.neviyn.observationdatabase.NameValue
import uk.co.neviyn.observationdatabase.NewObservation
import uk.co.neviyn.observationdatabase.NewSite
import uk.co.neviyn.observationdatabase.NewTutor
import uk.co.neviyn.observationdatabase.Observation
import uk.co.neviyn.observationdatabase.ObservationRepository
import uk.co.neviyn.observationdatabase.ObservationsRequest
import uk.co.neviyn.observationdatabase.Person
import uk.co.neviyn.observationdatabase.PersonRepository
import uk.co.neviyn.observationdatabase.Site
import uk.co.neviyn.observationdatabase.SiteRepository
import uk.co.neviyn.observationdatabase.Tutor
import uk.co.neviyn.observationdatabase.TutorRepository
import javax.validation.Valid import javax.validation.Valid
@RestController @RestController
@RequestMapping("/api") @RequestMapping("/api")
@CrossOrigin @CrossOrigin
class Controller { class ObservationsController {
private val logger: Logger = LoggerFactory.getLogger(javaClass)!! private val logger: Logger = LoggerFactory.getLogger(javaClass)!!
@Autowired
lateinit var environment: Environment
@Autowired @Autowired
lateinit var siteRepository: SiteRepository lateinit var siteRepository: SiteRepository
@Autowired @Autowired
@ -148,8 +159,8 @@ class Controller {
logger.debug("Observation contains a tutor") logger.debug("Observation contains a tutor")
return tutorRepository.findById(observationsRequest.tutor).map { return tutorRepository.findById(observationsRequest.tutor).map {
observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(tutor = it, observationRepository.findByTutorsAndDateBetweenOrderByDateAsc(tutor = it,
startDate = observationsRequest.startDate, startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate) endDate = observationsRequest.endDate)
}.orElse(listOf()) }.orElse(listOf())
} else if (observationsRequest.person != null && observationsRequest.person.isNotEmpty() && observationsRequest.site != null) { } else if (observationsRequest.person != null && observationsRequest.person.isNotEmpty() && observationsRequest.site != null) {
logger.debug("Observation contains a person") logger.debug("Observation contains a person")
@ -160,8 +171,8 @@ class Controller {
logger.debug("Observation contains a site") logger.debug("Observation contains a site")
return siteRepository.findById(observationsRequest.site).map { return siteRepository.findById(observationsRequest.site).map {
observationRepository.findBySiteAndDateBetweenOrderByDateAsc(site = it, observationRepository.findBySiteAndDateBetweenOrderByDateAsc(site = it,
startDate = observationsRequest.startDate, startDate = observationsRequest.startDate,
endDate = observationsRequest.endDate) endDate = observationsRequest.endDate)
}.orElse(listOf()) }.orElse(listOf())
} else { } else {
logger.error("Observation request contains no data from which a request can be made\n$observationsRequest") logger.error("Observation request contains no data from which a request can be made\n$observationsRequest")
@ -262,93 +273,4 @@ class Controller {
} }
return AfiPieChart(AfiPieChartDataset(monitoring, knowledge, control, conservatism, teamwork)) return AfiPieChart(AfiPieChartDataset(monitoring, knowledge, control, conservatism, teamwork))
} }
}
@PostMapping("/grpob/start")
fun startGroupObservation(initData: GroupObservationInit): Map<String, String> {
val site = siteRepository.findById(initData.site)
val tutors = tutorRepository.findAllById(initData.tutors).toSet()
if (!site.isPresent) {
logger.info("Attempted to add Observation without a site.")
return mapOf("error" to "Site required")
}
if (tutors.isEmpty() || tutors.size != initData.tutors.size) {
logger.info("Attempted to add Observation without a tutor")
return mapOf("error" to "Tutor(s) required")
}
val sessionId = GroupSessionManager.startNewSession(site.get(), tutors, initData.type, initData.scenarioTitles)
return getConnectionDetails().plus("id" to sessionId.toString())
}
@GetMapping("/grpob/recover")
fun reconnectToGroupObservation(): Map<String, Any> {
logger.debug("Previous group observation requested")
return getConnectionDetails().plus(mapOf("id" to GroupSessionManager.sessionId.toString(), "observations" to GroupSessionManager.observations))
}
@GetMapping("/grpob/valid/{id}")
fun checkGroupObservationValidityById(@PathVariable id: Int): Map<String, Any> {
if (GroupSessionManager.isValid(id)) {
return mapOf("titles" to GroupSessionManager.scenarioTitles!!)
}
logger.warn("Group observation requested with id $id but there is no valid session")
return mapOf("error" to "no valid session")
}
@GetMapping("/grpob/valid")
fun checkGroupObservationValidity(): Boolean {
return GroupSessionManager.isValid()
}
@PostMapping("/grpob/submit")
fun addGroupObservation(observationData: GroupObservation) {
if (GroupSessionManager.isValid()) {
var observation = Observation(
site = GroupSessionManager.site!!,
date = LocalDate.now(),
type = GroupSessionManager.trainingType!!,
observed = observationData.scenarios.joinToString { it.title },
monitoring = observationData.scenarios.map { it.monitoring.rating }.average(),
conservatism = observationData.scenarios.map { it.conservatism.rating }.average(),
controlProcedural = observationData.scenarios.map { it.controlProcedural.rating }.average(),
control = observationData.scenarios.map { it.control.rating }.average(),
teamworkCommunications = observationData.scenarios.map { it.teamworkCommunications.rating }.average(),
teamworkLeadership = observationData.scenarios.map { it.teamworkLeadership.rating }.average(),
teamworkWorkload = observationData.scenarios.map { it.teamworkWorkload.rating }.average(),
knowledge = observationData.scenarios.map { it.knowledge.rating }.average(),
scenarios = observationData.scenarios,
tutors = GroupSessionManager.tutors!!,
person = personRepository.findFirstByNameLike(observationData.person.toUpperCase()) ?: personRepository.save(Person(name = observationData.person.toUpperCase()))
)
observation = saveObservation(observation)
GroupSessionManager.addObservation(observation)
}
}
@GetMapping("/address")
fun getConnectionDetails(): Map<String, String> {
var ipv4: String? = null
var retryCount = 0
while (ipv4 == null && retryCount < 3) {
ipv4 = NetworkInterface.getNetworkInterfaces().asSequence()
.filter { !it.isLoopback }.map { x -> x.inetAddresses.asSequence()
.filter { it is Inet4Address }.map { it.hostAddress } }.flatten().firstOrNull()
retryCount++
Thread.sleep(1_000) // Sleep for 1 second
}
if (ipv4 != null)
return mapOf("ip" to ipv4, "port" to environment["local.server.port"])
return mapOf("error" to "Could not determine IP Address")
}
}
data class AverageData(
val monitoring: Double,
val controlProcedural: Double,
val control: Double,
val conservatism: Double,
val teamworkCommunications: Double,
val teamworkLeadership: Double,
val teamworkWorkload: Double,
val knowledge: Double,
val date: LocalDate
)

View File

@ -6,16 +6,21 @@ import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.junit4.SpringRunner import org.springframework.test.context.junit4.SpringRunner
import uk.co.neviyn.observationdatabase.controller.GroupSessionController
import uk.co.neviyn.observationdatabase.controller.ObservationsController
@RunWith(SpringRunner::class) @RunWith(SpringRunner::class)
@SpringBootTest @SpringBootTest
class ObservationDatabaseApplicationTests { class ObservationDatabaseApplicationTests {
@Autowired @Autowired
lateinit var controller: Controller lateinit var observationsController: ObservationsController
@Autowired
lateinit var groupSessionController: GroupSessionController
@Test @Test
fun contextLoads() { fun contextLoads() {
assertNotNull(controller) assertNotNull(observationsController)
assertNotNull(groupSessionController)
} }
} }

View File

@ -7,13 +7,14 @@ import org.junit.runner.RunWith
import org.mockito.* import org.mockito.*
import org.mockito.Mockito.* import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnitRunner import org.mockito.junit.MockitoJUnitRunner
import uk.co.neviyn.observationdatabase.controller.ObservationsController
import java.util.* import java.util.*
@RunWith(MockitoJUnitRunner::class) @RunWith(MockitoJUnitRunner::class)
class ControllerTest { class ObservationsControllerTest {
@InjectMocks @InjectMocks
lateinit var controller: Controller lateinit var controller: ObservationsController
@Mock @Mock
lateinit var siteRepository: SiteRepository lateinit var siteRepository: SiteRepository