From e9caea5b097e1f2e4ca4e12dee46c3dbd6973d45 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Fri, 3 May 2024 12:29:17 +0200 Subject: [PATCH 01/10] Implement ObservationsListDto return type --- data-dashboard-backend/dev/dashboard.yml | 4 +- .../datadashboard/api/api/ObservationDto.kt | 9 ++ ...riableListDto.kt => ObservationListDto.kt} | 4 +- .../datadashboard/api/api/VariableDto.kt | 37 ------- .../api/domain/ObservationRepository.kt | 28 +++--- .../api/domain/mapper/Extensions.kt | 24 +---- .../api/domain/model/Observation.kt | 51 +++++----- .../api/domain/model/Variable.kt | 67 ------------- .../enhancer/DashBoardApiEnhancerFactory.kt | 4 +- .../api/resource/ObservationResource.kt | 9 +- .../api/service/ObservationService.kt | 9 +- .../changes/20220309-create-database.xml | 64 +++++------- .../changes/20220321-insert-mock-data.xml | 36 ++----- .../changes/20220321-observations.csv | 9 ++ .../api/DashboardIntegrationTest.kt | 20 ++-- .../api/resource/ObservationResourceTest.kt | 98 +++++++++++++++++++ .../api/service/ObservationServiceTest.kt | 75 ++++++++++++++ 17 files changed, 287 insertions(+), 261 deletions(-) rename data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/{VariableListDto.kt => ObservationListDto.kt} (90%) delete mode 100644 data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableDto.kt delete mode 100644 data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Variable.kt create mode 100644 data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv create mode 100644 data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt create mode 100644 data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt diff --git a/data-dashboard-backend/dev/dashboard.yml b/data-dashboard-backend/dev/dashboard.yml index 14e86c6..c2e0cc5 100644 --- a/data-dashboard-backend/dev/dashboard.yml +++ b/data-dashboard-backend/dev/dashboard.yml @@ -5,13 +5,13 @@ service: auth: managementPortal: - url: http://localhost:8080/managementportal + url: http://127.0.0.1:8080/managementportal clientId: data_dashboard_api clientSecret: data_dashboard_api_secret jwtResourceName: res_DataDashboardAPI database: - url: jdbc:postgresql://localhost:5432/data + url: jdbc:postgresql://127.0.0.1:5432/data user: radarbase password: radarbase dialect: org.hibernate.dialect.PostgreSQLDialect diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt index 3317c15..73ddc03 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt @@ -23,6 +23,15 @@ data class ObservationDto( /** Unique observation ID. */ val id: Long?, + /** Unique identifier of study subject. */ + val subject: String?, + + /** Unique identifier of the kafka topic. */ + val topic: String?, + + /** Category of the observation (optional). */ + val category: String?, + /** Date or date-time of the observation. */ val date: String?, diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableListDto.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationListDto.kt similarity index 90% rename from data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableListDto.kt rename to data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationListDto.kt index 761a397..85eb17b 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableListDto.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationListDto.kt @@ -19,6 +19,6 @@ package org.radarbase.datadashboard.api.api /** List of variables. */ -data class VariableListDto( - val variables: List, +data class ObservationListDto( + val observations: List, ) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableDto.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableDto.kt deleted file mode 100644 index 7997a5f..0000000 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/VariableDto.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * * Copyright 2024 The Hyve - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * - */ - -package org.radarbase.datadashboard.api.api - -import org.radarbase.datadashboard.api.domain.model.Variable - -/** A variable, describing a type of observations. */ -data class VariableDto( - /** Unique ID. */ - val id: Long?, - /** Canonical name of the variable. */ - val name: String, - /** Data type of observations for this variable. */ - val type: String?, - /** Category to group variables with. */ - val category: String?, - /** Observations that are selected for this variable. */ - val observations: List?, - /** Date type of observations. */ - val dateType: Variable.DateType? = Variable.DateType.LOCAL_DATE, -) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt index 0a15ebd..5db3759 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt @@ -20,30 +20,26 @@ package org.radarbase.datadashboard.api.domain import jakarta.inject.Provider import jakarta.persistence.EntityManager -import jakarta.persistence.Tuple import jakarta.ws.rs.core.Context +import org.radarbase.datadashboard.api.domain.model.Observation import org.radarbase.jersey.hibernate.HibernateRepository import org.slf4j.LoggerFactory - class ObservationRepository( @Context em: Provider, ) : HibernateRepository(em) { - fun getObservations(topicId: String, subjectId: String): List> { - logger.debug("Get observations of topic {} and subject {}", topicId, subjectId) - val rows: List = transact { - createNativeQuery( - "SELECT * FROM ${topicId} o WHERE o.userId = '${subjectId}' ORDER BY o.timestamp DESC", - Tuple::class.java - ).resultList - } - // Create a list of maps from the rows. - return rows.map { row -> - (row as Tuple).elements.associate { - // Column name is the key, value is the database value. - it.alias to row.get(it.alias) - } + fun getObservations(topicId: String, subjectId: String): List { + logger.debug("Get observations in topic {} of subject {}", topicId, subjectId) + + return transact { + createQuery( + "SELECT o FROM Observation o WHERE o.subject = :subjectId AND o.topic = :topicId ORDER BY o.date DESC", + Observation::class.java, + ).apply { + setParameter("subjectId", subjectId) + setParameter("topicId", topicId) + }.resultList } } diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt index 5086efd..dc31d71 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt @@ -19,13 +19,14 @@ package org.radarbase.datadashboard.api.domain.mapper import org.radarbase.datadashboard.api.api.ObservationDto -import org.radarbase.datadashboard.api.api.VariableDto import org.radarbase.datadashboard.api.domain.model.Observation -import org.radarbase.datadashboard.api.domain.model.Variable import java.time.Duration fun Observation.toDto(): ObservationDto = ObservationDto( id = id, + subject = subject, + topic = topic, + category = category, date = date?.toString(), period = if (date != null && endDate != null) { Duration.between(date, endDate).toString() @@ -35,22 +36,3 @@ fun Observation.toDto(): ObservationDto = ObservationDto( value = valueNumeric ?: valueTextual, ) -fun Map.Entry>.toDto(): VariableDto { - val (variable, observations) = this - return variable.toDto( - observations - .sortedBy { it.date } - .map { it.toDto() }, - ) -} - -fun Variable.toDtoWithoutObservations(): VariableDto = toDto(null) - -fun Variable.toDto(observations: List?): VariableDto = VariableDto( - id = id, - name = name, - type = type, - category = category, - observations = observations, - dateType = dateType, -) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt index 2120053..f464445 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt @@ -24,48 +24,55 @@ import java.util.* @Entity @Table(name = "observation") -class Observation( +data class Observation( @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(updatable = false, nullable = false) @Id - val id: Long?, - @Column(name = "subject_id") - val subjectId: String, - @ManyToOne - @JoinColumn(name = "variable_id") - val variable: Variable, - val date: ZonedDateTime?, + val id: Long, + + @Column(nullable = false) + @Id + val subject: String, + + @Column(nullable = false) + @Id + val topic: String, + + @Id + val category: String, + + @Column(nullable = false) + @Id + val variable: String, + + @Column(nullable = false) + @Id + val date: ZonedDateTime, + @Column(name = "end_date") val endDate: ZonedDateTime?, + @Column(name = "value_textual") val valueTextual: String?, + @Column(name = "value_numeric") val valueNumeric: Double?, + ) { override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false other as Observation - if (id != null && other.id != null) { - return id == other.id - } - - return subjectId == other.subjectId && + return subject == other.subject && + topic == other.topic && + category == other.category && variable == other.variable && date == other.date && endDate == other.endDate } - override fun hashCode(): Int = Objects.hash(subjectId, variable, date) - - override fun toString(): String = "Observation(" + - "id=$id, " + - "variable=$variable, " + - "date=$date, " + - "endDate=$endDate, " + - "valueTextual=${valueTextual.toPrintString()}, " + - "valueNumeric=$valueNumeric)" + override fun hashCode(): Int = Objects.hash(subject, variable, date) companion object { internal fun String?.toPrintString() = if (this != null) "'$this'" else "null" diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Variable.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Variable.kt deleted file mode 100644 index 104bcf8..0000000 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Variable.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * - * * Copyright 2024 The Hyve - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * - */ - -package org.radarbase.datadashboard.api.domain.model - -import org.radarbase.datadashboard.api.domain.model.Observation.Companion.toPrintString -import jakarta.persistence.* - -@Entity -@Table(name = "variable") -class Variable( - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Id - val id: Long?, - val name: String, - val type: String?, - val category: String?, - @OneToMany(mappedBy = "variable", fetch = FetchType.LAZY) - val observations: List, - @Enumerated(EnumType.STRING) - @Column(name = "date_type") - val dateType: DateType? = DateType.LOCAL_DATE, -) { - enum class DateType { - LOCAL_DATE, ZONED_DATE, LOCAL_DATE_TIME, ZONED_DATE_TIME, - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (javaClass != other?.javaClass) return false - - other as Variable - - if (id != null && other.id != null) { - return id == other.id - } - - return name == other.name && - type == other.type && - category == other.category && - dateType == other.dateType - } - - override fun hashCode(): Int = name.hashCode() - - override fun toString(): String = "Variable(" + - "id=$id, " + - "name='$name', " + - "type=${type.toPrintString()}, " + - "category=${category.toPrintString()}, " + - "dateType=$dateType)" -} diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt index af24ae3..7dec3d3 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt @@ -20,7 +20,6 @@ package org.radarbase.datadashboard.api.enhancer import org.radarbase.datadashboard.api.config.DashboardApiConfig import org.radarbase.datadashboard.api.domain.model.Observation -import org.radarbase.datadashboard.api.domain.model.Variable import org.radarbase.jersey.enhancer.EnhancerFactory import org.radarbase.jersey.enhancer.Enhancers import org.radarbase.jersey.enhancer.JerseyResourceEnhancer @@ -40,8 +39,7 @@ class DashBoardApiEnhancerFactory( HibernateResourceEnhancer( config.database.copy( managedClasses = listOf( - Observation::class.jvmName, - Variable::class.jvmName + Observation::class.jvmName ), ), ), diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt index 6f18fd1..34616fc 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt @@ -23,12 +23,12 @@ import jakarta.ws.rs.* import jakarta.ws.rs.container.ContainerRequestContext import jakarta.ws.rs.core.Context import jakarta.ws.rs.core.Response -import org.radarbase.datadashboard.api.api.VariableListDto import org.radarbase.datadashboard.api.service.ObservationService import org.radarbase.auth.authorization.Permission +import org.radarbase.datadashboard.api.api.ObservationDto +import org.radarbase.datadashboard.api.api.ObservationListDto import org.radarbase.jersey.auth.Authenticated import org.radarbase.jersey.auth.NeedsPermission -import org.radarbase.jersey.auth.filter.RadarSecurityContext @Path("subject/{subjectId}/topic/{topicId}") @Resource @@ -36,8 +36,7 @@ import org.radarbase.jersey.auth.filter.RadarSecurityContext @Consumes("application/json") @Authenticated class ObservationResource( - @Context private val observationService: ObservationService, - @Context private val request: ContainerRequestContext + @Context private val observationService: ObservationService ) { @GET @Path("observations") @@ -45,7 +44,7 @@ class ObservationResource( fun getObservations( @PathParam("subjectId") subjectId: String, @PathParam("topicId") topicId: String - ): List> { + ): ObservationListDto { // if (request.securityContext != null && request.securityContext is RadarSecurityContext) { // val userName = (request.securityContext as RadarSecurityContext).userPrincipal // if (!subjectId.equals(userName)) throw NotFoundException("Subjects can only access their own data.") diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt index 7fe9047..5086be2 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt @@ -19,14 +19,17 @@ package org.radarbase.datadashboard.api.service import jakarta.ws.rs.core.Context -import org.radarbase.datadashboard.api.api.VariableListDto +import org.radarbase.datadashboard.api.api.ObservationListDto import org.radarbase.datadashboard.api.domain.ObservationRepository import org.radarbase.datadashboard.api.domain.mapper.toDto class ObservationService( @Context private val observationRepository: ObservationRepository ) { - fun getObservations(topicId: String, subjectId: String): List> { - return this.observationRepository.getObservations(topicId, subjectId) + fun getObservations(topicId: String, subjectId: String): ObservationListDto { + val result = this.observationRepository.getObservations(topicId, subjectId) + return ObservationListDto( + result.map { it.toDto() }, + ) } } diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml index c879c52..61c14aa 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml @@ -21,53 +21,35 @@ xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd"> + - - Create topic tables - - - - + + + + - - + + - - + + - - + + + - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - + + + - + + + + + + diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-insert-mock-data.xml b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-insert-mock-data.xml index 5ef108d..4a4c0f5 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-insert-mock-data.xml +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-insert-mock-data.xml @@ -22,38 +22,14 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd"> - + - - - - + tableName="observation" + usePreparedStatements="true"> + + - - - - - - - - - - - - - - - - diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv new file mode 100644 index 0000000..c7f744e --- /dev/null +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv @@ -0,0 +1,9 @@ +subject;topic;category;variable;value_numeric;value_textual;date;end_date +sub-1;questionnaire_answer;baseline_questions;Perceived_Pain_Score;5;NULL;2021-02-20 00:00:00;NULL +sub-1;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.J.Adams;2021-02-20 00:00:00;NULL +sub-2;questionnaire_answer;baseline_questions;Perceived_Pain_Score;2;NULL;2021-02-20 00:00:00;NULL +sub-2;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.G.Washington;2022-05-20 00:00:00;NULL +sub-1;phone_battery_level;NULL;batteryLevel;5;NULL;2021-02-20 00:00:00;NULL +sub-1;phone_battery_level;NULL;status;NULL;CHARGING;2021-02-20 00:00:00;NULL +sub-2;phone_battery_level;NULL;batteryLevel;10;NULL;2021-02-20 00:00:00;NULL +sub-2;phone_battery_level;NULL;status;NULL;FULL;2021-02-20 00:00:00;NULL diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt index c493544..07ea8a5 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt @@ -28,15 +28,15 @@ import org.glassfish.jersey.test.ServletDeploymentContext import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory import org.glassfish.jersey.test.spi.TestContainerFactory import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.radarbase.datadashboard.api.config.DashboardApiConfig +import org.radarbase.datadashboard.api.resource.ObservationResource import org.radarbase.jersey.auth.AuthValidator import org.radarbase.jersey.auth.disabled.DisabledAuthValidator import org.radarbase.jersey.config.ConfigLoader -class DashboardIntegrationTest : JerseyTest() { +class DashboardIntegrationTest: JerseyTest() { lateinit var disabledAuthValidator: DisabledAuthValidator @@ -49,6 +49,7 @@ class DashboardIntegrationTest : JerseyTest() { bind(disabledAuthValidator).to(AuthValidator::class.java).ranked(1) } }) + resourceConfig.register(ObservationResource::class.java) return resourceConfig } @@ -69,22 +70,17 @@ class DashboardIntegrationTest : JerseyTest() { } @Test - @Disabled("Manageportal authentication does not yet work (always code 200 returned)") fun testGetObservationsNoToken() { - val response = - target("subject/f09c03f1-617d-4c2b-b093-4936f75092fa/topic/android_phone_battery_level/observations").request() - .get() + val response = target("subject/sub-1/topic/phone_battery_level/observations").request().get() Assertions.assertEquals(401, response.status) } @Test fun testGetObservationsWithToken() { - val response = - target("subject/f09c03f1-617d-4c2b-b093-4936f75092fa/topic/android_phone_battery_level/observations") - .request() - .header(HttpHeaders.AUTHORIZATION, "Bearer " + "... encoded token ...") - .get() - val a = response.readEntity(String::class.java) + val response = target("subject/sub-1/topic/phone_battery_level/observations") + .request() + .header(HttpHeaders.AUTHORIZATION, "Bearer " + "... encoded token ...") + .get() Assertions.assertEquals(200, response.status) } diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt new file mode 100644 index 0000000..fdcd68c --- /dev/null +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt @@ -0,0 +1,98 @@ +/* + * + * * Copyright 2024 The Hyve + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.radarbase.datadashboard.api.resource + +import jakarta.ws.rs.core.Application +import org.glassfish.hk2.utilities.binding.AbstractBinder +import org.glassfish.jersey.server.ResourceConfig +import org.glassfish.jersey.test.JerseyTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import org.radarbase.datadashboard.api.api.ObservationListDto +import org.radarbase.datadashboard.api.domain.mapper.toDto +import org.radarbase.datadashboard.api.domain.model.Observation +import org.radarbase.datadashboard.api.service.ObservationService +import java.time.ZonedDateTime + +class ObservationResourceTest: JerseyTest() { + + + @Mock + lateinit var observationService: ObservationService + + private lateinit var observationListDto: ObservationListDto + private val subjectId = "sub-1" + private val topicId = "topic-1" + + override fun configure(): Application { + // Initialize all defined Mockito mocks (with @Mock annotation). + MockitoAnnotations.openMocks(this) + // Configure the Jersey Application. + val resourceConfig = ResourceConfig(ObservationResource::class.java) + // Register the ObservationService mock for dependency injection (needed by ObservationResource). + resourceConfig.register(object : AbstractBinder() { + override fun configure() { + bind(observationService).to(ObservationService::class.java) + } + }) + return resourceConfig + } + + @BeforeEach + fun init() { + // Create some fake observations that are returned by the service. + val obs1 = Observation(id = 1L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs2 = Observation(id = 2L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs3 = Observation(id = 3L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs4 = Observation(id = 4L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val observations: List = listOf(obs1, obs2, obs3, obs4) + // Create Dto that should be returned by the ObservationService. + observationListDto = ObservationListDto( + observations.map { it.toDto() }, + ) + } + + @Test + fun testGetObservations() { + // Instruct the mock to return the fake observations when called. + `when`(observationService.getObservations(subjectId = subjectId, topicId = topicId)).thenReturn(observationListDto) + // Make the call to the REST endpoint. + val response = target("subject/sub-1/topic/topic-1/observations").request().get() + // Expect the http response to be OK and the same as the expected DTO. + assertEquals(200, response.status) + assertEquals(observationListDto, response.readEntity(ObservationListDto::class.java)) + } + + @Test + fun testGetObservations_failNoSubjectId() { + val response = target("subject//topic/topic-1/observations").request().get() + assertEquals(404, response.status) + } + + @Test + fun testGetObservations_failNoTopicId() { + val response = target("subject/sub-1/topic//observations").request().get() + assertEquals(404, response.status) + } + +} \ No newline at end of file diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt new file mode 100644 index 0000000..5fb1e1d --- /dev/null +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt @@ -0,0 +1,75 @@ +/* + * + * * Copyright 2024 The Hyve + * * + * * Licensed under the Apache License, Version 2.0 (the "License"); + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * + */ + +package org.radarbase.datadashboard.api.service + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.mockito.Mock +import org.mockito.Mockito.`when` +import org.mockito.MockitoAnnotations +import org.radarbase.datadashboard.api.api.ObservationListDto +import org.radarbase.datadashboard.api.domain.ObservationRepository +import org.radarbase.datadashboard.api.domain.mapper.toDto +import org.radarbase.datadashboard.api.domain.model.Observation +import java.time.ZonedDateTime + +class ObservationServiceTest { + + val subjectId = "sub-1" + + // Create a Mockito mock of the ObservationRepository. This is instantiated in the init block. + @Mock + private lateinit var observationRepository: ObservationRepository + + private val observationService: ObservationService + + init { + // Initialize all Mockito mocks. + MockitoAnnotations.openMocks(this) + observationService = ObservationService(observationRepository) + } + + /** This test does not test much (only whether the service calls the repository). + * I made it mainly to document how to write a test with mocking. + * */ + @Test + fun test_getObservations1() { + + // Create some fake observations that are returned by the repository. + // Each observation is linked to a Variable. + val obs1 = Observation(id = 1L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs2 = Observation(id = 2L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs3 = Observation(id = 3L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val obs4 = Observation(id = 4L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) + val observations = listOf(obs1, obs2, obs3, obs4) + + // Mock the repository to return the fake observations. + `when`(observationRepository.getObservations(subjectId = subjectId, topicId = "topic-1")).thenReturn(observations) + + // Call the ObservationService (class under test) to get the observations. + val result = observationService.getObservations(subjectId = subjectId, topicId = "topic-1") + + // Check if the result is as expected (observations transformed to ObservationListDto). + val expectedDto = ObservationListDto( + observations.map { it.toDto() } + ) + assertEquals(expectedDto, result) + } + +} \ No newline at end of file From dba5437a25159050be3eacf58605e97f40171819 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Fri, 3 May 2024 12:41:24 +0200 Subject: [PATCH 02/10] Enable check of user --- .../api/resource/ObservationResource.kt | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt index 34616fc..9770b9c 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt @@ -22,13 +22,13 @@ import jakarta.annotation.Resource import jakarta.ws.rs.* import jakarta.ws.rs.container.ContainerRequestContext import jakarta.ws.rs.core.Context -import jakarta.ws.rs.core.Response import org.radarbase.datadashboard.api.service.ObservationService import org.radarbase.auth.authorization.Permission -import org.radarbase.datadashboard.api.api.ObservationDto import org.radarbase.datadashboard.api.api.ObservationListDto import org.radarbase.jersey.auth.Authenticated import org.radarbase.jersey.auth.NeedsPermission +import org.radarbase.jersey.auth.filter.RadarSecurityContext +import org.slf4j.LoggerFactory @Path("subject/{subjectId}/topic/{topicId}") @Resource @@ -36,7 +36,8 @@ import org.radarbase.jersey.auth.NeedsPermission @Consumes("application/json") @Authenticated class ObservationResource( - @Context private val observationService: ObservationService + @Context private val observationService: ObservationService, + @Context private val request: ContainerRequestContext ) { @GET @Path("observations") @@ -45,11 +46,16 @@ class ObservationResource( @PathParam("subjectId") subjectId: String, @PathParam("topicId") topicId: String ): ObservationListDto { -// if (request.securityContext != null && request.securityContext is RadarSecurityContext) { -// val userName = (request.securityContext as RadarSecurityContext).userPrincipal -// if (!subjectId.equals(userName)) throw NotFoundException("Subjects can only access their own data.") + if (request.securityContext != null && request.securityContext is RadarSecurityContext) { + val userName = (request.securityContext as RadarSecurityContext).userPrincipal + log.info("User $userName is accessing observations for $subjectId") + if (!subjectId.equals(userName)) throw NotFoundException("Subjects can only request their own observations.") return observationService.getObservations(topicId, subjectId) -// } -// return emptyList() + } + return ObservationListDto(emptyList()) + } + + companion object { + private val log = LoggerFactory.getLogger(ObservationResource::class.java) } } From 614f1b76c2d1d0437bc99283d9cafffe78a0c1c8 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Fri, 3 May 2024 12:57:47 +0200 Subject: [PATCH 03/10] Only create tables when running in dev mode --- .../resources/db/changelog/changes/20220309-create-database.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml index 61c14aa..41c6b51 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml @@ -23,7 +23,7 @@ https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.6.xsd"> - + From a08d811adc8d8a8ba862606103b6f0ed85c7bdcf Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Fri, 3 May 2024 12:58:16 +0200 Subject: [PATCH 04/10] Publish docker images on GitHub and docker hub --- .github/workflows/docker-image.yml | 12 ++++++++---- .github/workflows/release.yml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 21a4e0c..03d0bd8 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -1,8 +1,6 @@ #See: https://docs.github.com/en/actions/publishing-packages/publishing-docker-images#publishing-images-to-github-packages name: Create and publish a Docker image -on: - release: - types: [ published ] +on: push env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} @@ -20,11 +18,17 @@ jobs: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Set environment variables + run: | + # Short name for current branch. For PRs, use target branch (base ref) + GIT_BRANCH=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}} + echo "GIT_BRANCH=$GIT_BRANCH" >> $GITHUB_ENV - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ env.GIT_BRANCH }} + tags: latest - name: Build and push Docker image uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f2fddaa..0cb936a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: id: docker_meta uses: docker/metadata-action@v4 with: - images: ${{ env.DOCKER_IMAGE }} + images: ${{ env.DOCKER_IMAGE }}-${{ env.GIT_BRANCH }} tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} From 42e111429e502a81822d1d248fd803eead3a9dbf Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Fri, 3 May 2024 15:26:30 +0200 Subject: [PATCH 05/10] Add project and source to Observation objects --- README.md | 2 +- .../datadashboard/api/api/ObservationDto.kt | 6 +++ .../api/domain/ObservationRepository.kt | 7 ++-- .../api/domain/mapper/Extensions.kt | 2 + .../api/domain/model/Observation.kt | 7 ++++ .../api/resource/ObservationResource.kt | 5 ++- .../api/service/ObservationService.kt | 4 +- .../changes/20220309-create-database.xml | 7 ++++ .../changes/20220321-observations.csv | 18 ++++----- .../api/DashboardIntegrationTest.kt | 4 +- .../api/resource/ObservationResourceTest.kt | 39 ++++++++++++++----- .../api/service/ObservationServiceTest.kt | 33 +++++++++++----- 12 files changed, 96 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index f6ac611..eb746b2 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ the data from the RADAR-base kafka service.[]\ Data dashboard applications can use the APIs as follows. -`GET */subject/{subjectId}/topic/{topicId}/observations` +`GET */project/{projectId}/subject/{subjectId}/topic/{topicId}/observations` ## Installation diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt index 73ddc03..eaf7d0b 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt @@ -23,9 +23,15 @@ data class ObservationDto( /** Unique observation ID. */ val id: Long?, + /** Unique identifier of project. */ + val project: String?, + /** Unique identifier of study subject. */ val subject: String?, + /** Unique identifier of the data source. */ + val source: String?, + /** Unique identifier of the kafka topic. */ val topic: String?, diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt index 5db3759..5f82150 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/ObservationRepository.kt @@ -29,14 +29,15 @@ class ObservationRepository( @Context em: Provider, ) : HibernateRepository(em) { - fun getObservations(topicId: String, subjectId: String): List { - logger.debug("Get observations in topic {} of subject {}", topicId, subjectId) + fun getObservations(projectId: String, subjectId: String, topicId: String): List { + logger.debug("Get observations in topic {} of subject {} in project {}", topicId, subjectId, projectId) return transact { createQuery( - "SELECT o FROM Observation o WHERE o.subject = :subjectId AND o.topic = :topicId ORDER BY o.date DESC", + "SELECT o FROM Observation o WHERE o.project = :projectId AND o.subject = :subjectId AND o.topic = :topicId ORDER BY o.date DESC", Observation::class.java, ).apply { + setParameter("projectId", projectId) setParameter("subjectId", subjectId) setParameter("topicId", topicId) }.resultList diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt index dc31d71..9d99177 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt @@ -24,7 +24,9 @@ import java.time.Duration fun Observation.toDto(): ObservationDto = ObservationDto( id = id, + project = project, subject = subject, + source = source, topic = topic, category = category, date = date?.toString(), diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt index f464445..cba018d 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt @@ -30,10 +30,17 @@ data class Observation( @Id val id: Long, + @Column(nullable = false) + @Id + val project: String, + @Column(nullable = false) @Id val subject: String, + @Id + val source: String, + @Column(nullable = false) @Id val topic: String, diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt index 9770b9c..3e3d4b9 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt @@ -30,7 +30,7 @@ import org.radarbase.jersey.auth.NeedsPermission import org.radarbase.jersey.auth.filter.RadarSecurityContext import org.slf4j.LoggerFactory -@Path("subject/{subjectId}/topic/{topicId}") +@Path("project/{projectId}/subject/{subjectId}/topic/{topicId}") @Resource @Produces("application/json") @Consumes("application/json") @@ -43,6 +43,7 @@ class ObservationResource( @Path("observations") @NeedsPermission(Permission.MEASUREMENT_READ) fun getObservations( + @PathParam("projectId") projectId: String, @PathParam("subjectId") subjectId: String, @PathParam("topicId") topicId: String ): ObservationListDto { @@ -50,7 +51,7 @@ class ObservationResource( val userName = (request.securityContext as RadarSecurityContext).userPrincipal log.info("User $userName is accessing observations for $subjectId") if (!subjectId.equals(userName)) throw NotFoundException("Subjects can only request their own observations.") - return observationService.getObservations(topicId, subjectId) + return observationService.getObservations(projectId = projectId, subjectId = subjectId, topicId = topicId) } return ObservationListDto(emptyList()) } diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt index 5086be2..9f5874c 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt @@ -26,8 +26,8 @@ import org.radarbase.datadashboard.api.domain.mapper.toDto class ObservationService( @Context private val observationRepository: ObservationRepository ) { - fun getObservations(topicId: String, subjectId: String): ObservationListDto { - val result = this.observationRepository.getObservations(topicId, subjectId) + fun getObservations(projectId: String, subjectId: String, topicId: String): ObservationListDto { + val result = this.observationRepository.getObservations(projectId = projectId, topicId = topicId, subjectId = subjectId) return ObservationListDto( result.map { it.toDto() }, ) diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml index 41c6b51..32c9ad9 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml @@ -28,9 +28,15 @@ + + + + + + @@ -47,6 +53,7 @@ + diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv index c7f744e..2d8302c 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220321-observations.csv @@ -1,9 +1,9 @@ -subject;topic;category;variable;value_numeric;value_textual;date;end_date -sub-1;questionnaire_answer;baseline_questions;Perceived_Pain_Score;5;NULL;2021-02-20 00:00:00;NULL -sub-1;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.J.Adams;2021-02-20 00:00:00;NULL -sub-2;questionnaire_answer;baseline_questions;Perceived_Pain_Score;2;NULL;2021-02-20 00:00:00;NULL -sub-2;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.G.Washington;2022-05-20 00:00:00;NULL -sub-1;phone_battery_level;NULL;batteryLevel;5;NULL;2021-02-20 00:00:00;NULL -sub-1;phone_battery_level;NULL;status;NULL;CHARGING;2021-02-20 00:00:00;NULL -sub-2;phone_battery_level;NULL;batteryLevel;10;NULL;2021-02-20 00:00:00;NULL -sub-2;phone_battery_level;NULL;status;NULL;FULL;2021-02-20 00:00:00;NULL +project;subject;source;topic;category;variable;value_numeric;value_textual;date;end_date +project-1;sub-1;source-1;questionnaire_answer;baseline_questions;Perceived_Pain_Score;5;NULL;2021-02-20 00:00:00;NULL +project-1;sub-1;source-1;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.J.Adams;2021-02-20 00:00:00;NULL +project-1;sub-2;source-1;questionnaire_answer;baseline_questions;Perceived_Pain_Score;2;NULL;2021-02-20 00:00:00;NULL +project-1;sub-2;source-1;questionnaire_answer;followup_questions;Name_Of_Physician;NULL;Dr.G.Washington;2022-05-20 00:00:00;NULL +project-1;sub-1;source-1;phone_battery_level;NULL;batteryLevel;5;NULL;2021-02-20 00:00:00;NULL +project-1;sub-1;source-1;phone_battery_level;NULL;status;NULL;CHARGING;2021-02-20 00:00:00;NULL +project-1;sub-2;source-1;phone_battery_level;NULL;batteryLevel;10;NULL;2021-02-20 00:00:00;NULL +project-1;sub-2;source-1;phone_battery_level;NULL;status;NULL;FULL;2021-02-20 00:00:00;NULL diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt index 07ea8a5..b73e411 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt @@ -71,13 +71,13 @@ class DashboardIntegrationTest: JerseyTest() { @Test fun testGetObservationsNoToken() { - val response = target("subject/sub-1/topic/phone_battery_level/observations").request().get() + val response = target("project/project-1/sub-1/topic/phone_battery_level/observations").request().get() Assertions.assertEquals(401, response.status) } @Test fun testGetObservationsWithToken() { - val response = target("subject/sub-1/topic/phone_battery_level/observations") + val response = target("project/project-1/subject/sub-1/topic/phone_battery_level/observations") .request() .header(HttpHeaders.AUTHORIZATION, "Bearer " + "... encoded token ...") .get() diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt index fdcd68c..20122d9 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt @@ -36,11 +36,12 @@ import java.time.ZonedDateTime class ObservationResourceTest: JerseyTest() { - @Mock lateinit var observationService: ObservationService private lateinit var observationListDto: ObservationListDto + private var observationId: Long = 1 + private val projectId = "project-1" private val subjectId = "sub-1" private val topicId = "topic-1" @@ -61,11 +62,7 @@ class ObservationResourceTest: JerseyTest() { @BeforeEach fun init() { // Create some fake observations that are returned by the service. - val obs1 = Observation(id = 1L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs2 = Observation(id = 2L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs3 = Observation(id = 3L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs4 = Observation(id = 4L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val observations: List = listOf(obs1, obs2, obs3, obs4) + val observations: List = listOf(createObservation(), createObservation(), createObservation(), createObservation()) // Create Dto that should be returned by the ObservationService. observationListDto = ObservationListDto( observations.map { it.toDto() }, @@ -75,9 +72,9 @@ class ObservationResourceTest: JerseyTest() { @Test fun testGetObservations() { // Instruct the mock to return the fake observations when called. - `when`(observationService.getObservations(subjectId = subjectId, topicId = topicId)).thenReturn(observationListDto) + `when`(observationService.getObservations(projectId = projectId, subjectId = subjectId, topicId = topicId)).thenReturn(observationListDto) // Make the call to the REST endpoint. - val response = target("subject/sub-1/topic/topic-1/observations").request().get() + val response = target("project/project-1/subject/sub-1/topic/topic-1/observations").request().get() // Expect the http response to be OK and the same as the expected DTO. assertEquals(200, response.status) assertEquals(observationListDto, response.readEntity(ObservationListDto::class.java)) @@ -85,14 +82,36 @@ class ObservationResourceTest: JerseyTest() { @Test fun testGetObservations_failNoSubjectId() { - val response = target("subject//topic/topic-1/observations").request().get() + val response = target("project/project-1/subject//topic/topic-1/observations").request().get() assertEquals(404, response.status) } @Test fun testGetObservations_failNoTopicId() { - val response = target("subject/sub-1/topic//observations").request().get() + val response = target("project/project-1/subject/sub-1/topic//observations").request().get() + assertEquals(404, response.status) + } + + @Test + fun testGetObservations_failNoProjectId() { + val response = target("project//subject/sub-1/topic/topic-1/observations").request().get() assertEquals(404, response.status) } + private fun createObservation(): Observation { + return Observation( + id = observationId, + project = "project-1", + subject = subjectId, + source = "source-1", + topic = "topic-1", + category = "category-1", + variable = "variable-1", + date = ZonedDateTime.now(), + valueTextual = "value1", + valueNumeric = null, + endDate = null + ) + } + } \ No newline at end of file diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt index 5fb1e1d..3d1b2f0 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt @@ -31,12 +31,15 @@ import java.time.ZonedDateTime class ObservationServiceTest { - val subjectId = "sub-1" - // Create a Mockito mock of the ObservationRepository. This is instantiated in the init block. @Mock private lateinit var observationRepository: ObservationRepository + private var observationId: Long = 1 + private val projectId = "project-1" + private val subjectId = "sub-1" + private val topicId = "topic-1" + private val observationService: ObservationService init { @@ -53,17 +56,13 @@ class ObservationServiceTest { // Create some fake observations that are returned by the repository. // Each observation is linked to a Variable. - val obs1 = Observation(id = 1L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs2 = Observation(id = 2L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs3 = Observation(id = 3L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val obs4 = Observation(id = 4L, subject = subjectId, topic = "topic-1", category = "category-1", variable = "variable-1", date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, endDate = null) - val observations = listOf(obs1, obs2, obs3, obs4) + val observations: List = listOf(createObservation(), createObservation(), createObservation(), createObservation()) // Mock the repository to return the fake observations. - `when`(observationRepository.getObservations(subjectId = subjectId, topicId = "topic-1")).thenReturn(observations) + `when`(observationRepository.getObservations(projectId = projectId, subjectId = subjectId, topicId = topicId)).thenReturn(observations) // Call the ObservationService (class under test) to get the observations. - val result = observationService.getObservations(subjectId = subjectId, topicId = "topic-1") + val result = observationService.getObservations(projectId = projectId, subjectId = subjectId, topicId = topicId) // Check if the result is as expected (observations transformed to ObservationListDto). val expectedDto = ObservationListDto( @@ -72,4 +71,20 @@ class ObservationServiceTest { assertEquals(expectedDto, result) } + private fun createObservation(): Observation { + return Observation( + id = observationId, + project = "project-1", + subject = subjectId, + source = "source-1", + topic = "topic-1", + category = "category-1", + variable = "variable-1", + date = ZonedDateTime.now(), + valueTextual = "value1", + valueNumeric = null, + endDate = null + ) + } + } \ No newline at end of file From 674599b00281f37bfea26a2ca19de76efbc99514 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Tue, 14 May 2024 13:16:07 +0200 Subject: [PATCH 06/10] Remove 'id' field from database schema --- .../radarbase/datadashboard/api/domain/mapper/Extensions.kt | 1 - .../radarbase/datadashboard/api/domain/model/Observation.kt | 5 ----- .../db/changelog/changes/20220309-create-database.xml | 3 --- .../datadashboard/api/resource/ObservationResourceTest.kt | 1 - .../datadashboard/api/service/ObservationServiceTest.kt | 1 - 5 files changed, 11 deletions(-) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt index 9d99177..4a1a299 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt @@ -23,7 +23,6 @@ import org.radarbase.datadashboard.api.domain.model.Observation import java.time.Duration fun Observation.toDto(): ObservationDto = ObservationDto( - id = id, project = project, subject = subject, source = source, diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt index cba018d..cae8c91 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt @@ -25,11 +25,6 @@ import java.util.* @Entity @Table(name = "observation") data class Observation( - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(updatable = false, nullable = false) - @Id - val id: Long, - @Column(nullable = false) @Id val project: String, diff --git a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml index 32c9ad9..dc9154b 100644 --- a/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml +++ b/data-dashboard-backend/src/main/resources/db/changelog/changes/20220309-create-database.xml @@ -25,9 +25,6 @@ - - - diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt index 20122d9..333fa1d 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt @@ -100,7 +100,6 @@ class ObservationResourceTest: JerseyTest() { private fun createObservation(): Observation { return Observation( - id = observationId, project = "project-1", subject = subjectId, source = "source-1", diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt index 3d1b2f0..aab6da5 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt @@ -73,7 +73,6 @@ class ObservationServiceTest { private fun createObservation(): Observation { return Observation( - id = observationId, project = "project-1", subject = subjectId, source = "source-1", From b990a8bfdf59efcb2bf9f255ea702f858ed8570a Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Tue, 14 May 2024 14:30:27 +0200 Subject: [PATCH 07/10] Fix linting errors --- .../datadashboard/api/api/ObservationDto.kt | 2 -- .../api/config/DashboardServiceConfig.kt | 2 +- .../datadashboard/api/domain/mapper/Extensions.kt | 5 ++--- .../datadashboard/api/domain/model/Observation.kt | 5 ++++- .../api/enhancer/DashBoardApiEnhancerFactory.kt | 2 +- .../api/enhancer/DashboardApiEnhancer.kt | 5 ++--- .../api/resource/ObservationResource.kt | 13 +++++++++---- .../datadashboard/api/service/ObservationService.kt | 2 +- .../datadashboard/api/DashboardIntegrationTest.kt | 4 +--- .../api/resource/ObservationResourceTest.kt | 7 +++---- .../api/service/ObservationServiceTest.kt | 8 +++----- 11 files changed, 27 insertions(+), 28 deletions(-) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt index eaf7d0b..a461531 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/api/ObservationDto.kt @@ -20,8 +20,6 @@ package org.radarbase.datadashboard.api.api /** Single observation or data point. */ data class ObservationDto( - /** Unique observation ID. */ - val id: Long?, /** Unique identifier of project. */ val project: String?, diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/config/DashboardServiceConfig.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/config/DashboardServiceConfig.kt index 4e08ba0..74149bb 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/config/DashboardServiceConfig.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/config/DashboardServiceConfig.kt @@ -40,4 +40,4 @@ data class DashboardServiceConfig( tokenExpiryTimeInMinutes = System.getenv("RADAR_DATA_DASHBOARD_TOKEN_EXPIRY_TIME_IN_MINUTES")?.toLong() ?: tokenExpiryTimeInMinutes, persistentTokenExpiryInMin = System.getenv("RADAR_DATA_DASHBOARD_PERSISTENT_TOKEN_EXPIRY_IN_MIN")?.toLong() ?: persistentTokenExpiryInMin, ) -} \ No newline at end of file +} diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt index 4a1a299..c6b46d8 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/mapper/Extensions.kt @@ -28,12 +28,11 @@ fun Observation.toDto(): ObservationDto = ObservationDto( source = source, topic = topic, category = category, - date = date?.toString(), - period = if (date != null && endDate != null) { + date = date.toString(), + period = if (endDate != null) { Duration.between(date, endDate).toString() } else { null }, value = valueNumeric ?: valueTextual, ) - diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt index cae8c91..2b4378e 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt @@ -18,7 +18,10 @@ package org.radarbase.datadashboard.api.domain.model -import jakarta.persistence.* +import jakarta.persistence.Column +import jakarta.persistence.Entity +import jakarta.persistence.Id +import jakarta.persistence.Table import java.time.ZonedDateTime import java.util.* diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt index 7dec3d3..9eea113 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashBoardApiEnhancerFactory.kt @@ -39,7 +39,7 @@ class DashBoardApiEnhancerFactory( HibernateResourceEnhancer( config.database.copy( managedClasses = listOf( - Observation::class.jvmName + Observation::class.jvmName, ), ), ), diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashboardApiEnhancer.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashboardApiEnhancer.kt index 42f8108..6e806b4 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashboardApiEnhancer.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/enhancer/DashboardApiEnhancer.kt @@ -18,11 +18,11 @@ package org.radarbase.datadashboard.api.enhancer +import jakarta.inject.Singleton +import org.glassfish.jersey.internal.inject.AbstractBinder import org.radarbase.datadashboard.api.config.DashboardApiConfig import org.radarbase.datadashboard.api.domain.ObservationRepository import org.radarbase.datadashboard.api.service.ObservationService -import jakarta.inject.Singleton -import org.glassfish.jersey.internal.inject.AbstractBinder import org.radarbase.jersey.enhancer.JerseyResourceEnhancer import org.radarbase.jersey.filter.Filters @@ -51,6 +51,5 @@ class DashboardApiEnhancer( bind(ObservationRepository::class.java) .to(ObservationRepository::class.java) .`in`(Singleton::class.java) - } } diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt index 3e3d4b9..ff6d948 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/resource/ObservationResource.kt @@ -19,12 +19,17 @@ package org.radarbase.datadashboard.api.resource import jakarta.annotation.Resource -import jakarta.ws.rs.* +import jakarta.ws.rs.Consumes +import jakarta.ws.rs.GET +import jakarta.ws.rs.NotFoundException +import jakarta.ws.rs.Path +import jakarta.ws.rs.PathParam +import jakarta.ws.rs.Produces import jakarta.ws.rs.container.ContainerRequestContext import jakarta.ws.rs.core.Context -import org.radarbase.datadashboard.api.service.ObservationService import org.radarbase.auth.authorization.Permission import org.radarbase.datadashboard.api.api.ObservationListDto +import org.radarbase.datadashboard.api.service.ObservationService import org.radarbase.jersey.auth.Authenticated import org.radarbase.jersey.auth.NeedsPermission import org.radarbase.jersey.auth.filter.RadarSecurityContext @@ -37,7 +42,7 @@ import org.slf4j.LoggerFactory @Authenticated class ObservationResource( @Context private val observationService: ObservationService, - @Context private val request: ContainerRequestContext + @Context private val request: ContainerRequestContext, ) { @GET @Path("observations") @@ -45,7 +50,7 @@ class ObservationResource( fun getObservations( @PathParam("projectId") projectId: String, @PathParam("subjectId") subjectId: String, - @PathParam("topicId") topicId: String + @PathParam("topicId") topicId: String, ): ObservationListDto { if (request.securityContext != null && request.securityContext is RadarSecurityContext) { val userName = (request.securityContext as RadarSecurityContext).userPrincipal diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt index 9f5874c..e2bc479 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/service/ObservationService.kt @@ -24,7 +24,7 @@ import org.radarbase.datadashboard.api.domain.ObservationRepository import org.radarbase.datadashboard.api.domain.mapper.toDto class ObservationService( - @Context private val observationRepository: ObservationRepository + @Context private val observationRepository: ObservationRepository, ) { fun getObservations(projectId: String, subjectId: String, topicId: String): ObservationListDto { val result = this.observationRepository.getObservations(projectId = projectId, topicId = topicId, subjectId = subjectId) diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt index b73e411..d1dd263 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/DashboardIntegrationTest.kt @@ -35,8 +35,7 @@ import org.radarbase.jersey.auth.AuthValidator import org.radarbase.jersey.auth.disabled.DisabledAuthValidator import org.radarbase.jersey.config.ConfigLoader - -class DashboardIntegrationTest: JerseyTest() { +class DashboardIntegrationTest : JerseyTest() { lateinit var disabledAuthValidator: DisabledAuthValidator @@ -85,5 +84,4 @@ class DashboardIntegrationTest: JerseyTest() { } // TODO add more tests that include the token validation. - } diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt index 333fa1d..a3e007e 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/resource/ObservationResourceTest.kt @@ -34,7 +34,7 @@ import org.radarbase.datadashboard.api.domain.model.Observation import org.radarbase.datadashboard.api.service.ObservationService import java.time.ZonedDateTime -class ObservationResourceTest: JerseyTest() { +class ObservationResourceTest : JerseyTest() { @Mock lateinit var observationService: ObservationService @@ -109,8 +109,7 @@ class ObservationResourceTest: JerseyTest() { date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, - endDate = null + endDate = null, ) } - -} \ No newline at end of file +} diff --git a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt index aab6da5..8c86c53 100644 --- a/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt +++ b/data-dashboard-backend/src/test/java/org/radarbase/datadashboard/api/service/ObservationServiceTest.kt @@ -53,7 +53,6 @@ class ObservationServiceTest { * */ @Test fun test_getObservations1() { - // Create some fake observations that are returned by the repository. // Each observation is linked to a Variable. val observations: List = listOf(createObservation(), createObservation(), createObservation(), createObservation()) @@ -66,7 +65,7 @@ class ObservationServiceTest { // Check if the result is as expected (observations transformed to ObservationListDto). val expectedDto = ObservationListDto( - observations.map { it.toDto() } + observations.map { it.toDto() }, ) assertEquals(expectedDto, result) } @@ -82,8 +81,7 @@ class ObservationServiceTest { date = ZonedDateTime.now(), valueTextual = "value1", valueNumeric = null, - endDate = null + endDate = null, ) } - -} \ No newline at end of file +} From 3a1d7b5ebcf81d00c5de36ecaf88f17d3fbee8b3 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 29 May 2024 10:27:21 +0200 Subject: [PATCH 08/10] Fix docker image name --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0cb936a..6bb4eb3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: types: [published] env: - DOCKER_IMAGE: radarbase/data-dashboard-backend + DOCKER_IMAGE: radarbase/radar-data-dashboard-backend jobs: # Build and push tagged release docker image From 68f176c35d26b4b886f7a4ec6a7d2bfd0de196f0 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 29 May 2024 10:30:15 +0200 Subject: [PATCH 09/10] Remove 'category' from primary key colums --- .../org/radarbase/datadashboard/api/domain/model/Observation.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt index 2b4378e..c642f31 100644 --- a/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt +++ b/data-dashboard-backend/src/main/java/org/radarbase/datadashboard/api/domain/model/Observation.kt @@ -43,7 +43,6 @@ data class Observation( @Id val topic: String, - @Id val category: String, @Column(nullable = false) From 93f56ac50d2ae230ef23eff6177b79150a390c17 Mon Sep 17 00:00:00 2001 From: Pim van Nierop Date: Wed, 29 May 2024 10:31:12 +0200 Subject: [PATCH 10/10] Update docs --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index eb746b2..ff0ce91 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,7 @@ The OAuth client for authorizer-app-backend should have the following properties ```properties client-id:data_dashboard_api client-secret:Confidential -grant-type:client_credentials +grant-type:authorization_code,refresh_token resources:res_DataDashboardAPI scope:MEASUREMENT.READ ``` -