From def22b7fea4cad531cac7318b09d6ca10075905b Mon Sep 17 00:00:00 2001 From: lucas-ifsp Date: Fri, 21 Jun 2024 11:13:40 -0300 Subject: [PATCH 001/153] feat: initial module commit for scas --- .idea/encodings.xml | 1 + pom.xml | 1 + .../create/CreateSearchSessionServiceImpl.kt | 7 ++ .../SelectionStatusSuggestionService.kt | 23 +++++ scas/pom.xml | 94 +++++++++++++++++++ .../kotlin/br/ifsp/octaviano/Principal.kt | 17 ++++ .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 11 +++ 7 files changed, 154 insertions(+) create mode 100644 review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt create mode 100644 scas/pom.xml create mode 100644 scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt create mode 100644 scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 05b89fd73..44efd8de8 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -7,6 +7,7 @@ + diff --git a/pom.xml b/pom.xml index 0fba64dbb..e0f2e0a6b 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ review web account + scas diff --git a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt index 58439bbd3..d13e3e6f4 100644 --- a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt @@ -56,8 +56,15 @@ class CreateSearchSessionServiceImpl( val searchSession = SearchSession.fromRequestModel(sessionId, request) val studyReviews = bibtexConverterService.convertManyToStudyReview(request.systematicStudyId.toSystematicStudyId() , file) + /* + criar os request StudyInfo a partir dos studyReviews (infos) + val selectionSuggestions = selectionSuggestion.buildSuggestions(infos) + studyReviews.foreach(it.setSuggestedStatus(selectionsuggstion.filter(it.getId) + */ studyReviewRepository.saveOrUpdateBatch(studyReviews.map { it.toDto() }) + + searchSessionRepository.create(searchSession.toDto()) presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, sessionId.value)) } diff --git a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt new file mode 100644 index 000000000..8f77e08c2 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt @@ -0,0 +1,23 @@ +package br.all.domain.services + +import br.all.domain.model.study.StudyReview + +interface SelectionStatusSuggestionService { + fun buildSuggestions(request: RequestModel) : ResponseModel + + data class RequestModel(val studiesInfo: List) + + data class ResponseModel(val studySuggestions: List) + + data class StudyReviewInfo( + val studyReviewId: Long, + val studyReviewScore: Int, + val studyReviewCitations: Int, + val studyReviewYear: Int + ) + + data class StudyStatusSuggestion( + val studyReviewId: Long, + val studyReviewScore: String, + ) +} \ No newline at end of file diff --git a/scas/pom.xml b/scas/pom.xml new file mode 100644 index 000000000..14a1e5fb8 --- /dev/null +++ b/scas/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + br.all + systematic + 1.0-SNAPSHOT + + + scas + + + UTF-8 + official + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + + + maven-failsafe-plugin + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + MainKt + + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 1.9.23 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.10.0 + test + + + org.jetbrains.kotlin + kotlin-stdlib + 1.9.23 + + + br.all + review + 1.0-SNAPSHOT + compile + + + + \ No newline at end of file diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt new file mode 100644 index 000000000..de2a88d45 --- /dev/null +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -0,0 +1,17 @@ +package br.ifsp.octaviano + +import br.all.domain.services.SelectionStatusSuggestionService +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel + +class Principal { + fun main(args: Array) { + val input = listOf( + SelectionStatusSuggestionService.StudyReviewInfo(1, 231, 3, 2023), + ) + + val service: SelectionStatusSuggestionService = ScasImpl() + val responseModel = service.buildSuggestions(RequestModel(input)) + + responseModel.studySuggestions.forEach { println(it) } + } +} \ No newline at end of file diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt new file mode 100644 index 000000000..869d4f444 --- /dev/null +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -0,0 +1,11 @@ +package br.ifsp.octaviano + +import br.all.domain.services.SelectionStatusSuggestionService +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.ResponseModel + +class ScasImpl : SelectionStatusSuggestionService { + override fun buildSuggestions(request: RequestModel): ResponseModel { + TODO("Not yet implemented") + } +} \ No newline at end of file From c89cb738e804fb68229662218c09068a7c7257ef Mon Sep 17 00:00:00 2001 From: Shoji Date: Tue, 20 Aug 2024 00:08:11 -0300 Subject: [PATCH 002/153] feat(scas): implement interface with approximate classification values --- .../SelectionStatusSuggestionService.kt | 6 +- .../kotlin/br/ifsp/octaviano/Principal.kt | 23 ++-- .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 110 +++++++++++++++++- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt index 8f77e08c2..3fa220dfd 100644 --- a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt +++ b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt @@ -1,13 +1,11 @@ package br.all.domain.services -import br.all.domain.model.study.StudyReview - interface SelectionStatusSuggestionService { fun buildSuggestions(request: RequestModel) : ResponseModel data class RequestModel(val studiesInfo: List) - data class ResponseModel(val studySuggestions: List) + data class ResponseModel(val studySuggestions: List) data class StudyReviewInfo( val studyReviewId: Long, @@ -20,4 +18,4 @@ interface SelectionStatusSuggestionService { val studyReviewId: Long, val studyReviewScore: String, ) -} \ No newline at end of file +} diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt index de2a88d45..5759f5378 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -1,17 +1,18 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.* -class Principal { - fun main(args: Array) { - val input = listOf( - SelectionStatusSuggestionService.StudyReviewInfo(1, 231, 3, 2023), - ) +fun main() { + val input = listOf( + StudyReviewInfo(1, 21, 10, 2023), + StudyReviewInfo(2, 0, 0, 2006), + StudyReviewInfo(3, 54, 40, 2023), + StudyReviewInfo(4, 34, 30, 2015), + ) - val service: SelectionStatusSuggestionService = ScasImpl() - val responseModel = service.buildSuggestions(RequestModel(input)) + val service: SelectionStatusSuggestionService = ScasImpl() + val responseModel = service.buildSuggestions(RequestModel(input)) - responseModel.studySuggestions.forEach { println(it) } - } -} \ No newline at end of file + responseModel.studySuggestions.forEach { println(it) } +} diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt index 869d4f444..8d6f2e63c 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -1,11 +1,113 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.RequestModel -import br.all.domain.services.SelectionStatusSuggestionService.ResponseModel +import br.all.domain.services.SelectionStatusSuggestionService.* class ScasImpl : SelectionStatusSuggestionService { + private enum class HazyValues { + LOW, MEDIUM, HIGH + } + + private data class StudyInfo( + val studyReviewId: Long, + val studyReviewScore: Int, + val studyReviewCitations: Int, + val studyReviewYear: Int, + var studyReviewNormalizedScore: Double? = null, + var studyScoreClassification: HazyValues? = null, + var studyReviewCitationCoefficient: Double? = null, + var studyReviewNormalizedCitationCoefficient: Double? = null, + var studyCitationCoefficientClassification: HazyValues? = null, + var studyReviewSuggestion: String? = null, + ) + override fun buildSuggestions(request: RequestModel): ResponseModel { - TODO("Not yet implemented") + val studiesInfo = convertToCompleteStudyInfo(request.studiesInfo) + + val mostRecentYear = getMostRecentYear(studiesInfo) + + calculateCitationCoefficients(studiesInfo, mostRecentYear) + normalizeScores(studiesInfo) + normalizeCitationCoefficients(studiesInfo) + classifyNormalizedScores(studiesInfo) + classifyNormalizedCitationCoefficients(studiesInfo) + val studySuggestions = suggestStudiesClassification(studiesInfo) + + return ResponseModel(studySuggestions) + } + + private fun convertToCompleteStudyInfo(studiesInfo: List): List { + return studiesInfo.map { + StudyInfo( + it.studyReviewId, it.studyReviewScore, it.studyReviewCitations, it.studyReviewYear + ) + } + } + + private fun getMostRecentYear(studiesInfo: List): Int { + val years = studiesInfo.map { it.studyReviewYear } + return years.max() + } + + private fun calculateCitationCoefficients( + studiesInfo: List, mostRecentYear: Int, index: Double = 0.05 + ) { + studiesInfo.forEach { + it.studyReviewCitationCoefficient = + (1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear)) + } + } + + private fun normalizeScores(studiesInfo: List) { + val scores = studiesInfo.map { it.studyReviewScore } + val max = scores.max() + studiesInfo.forEach { it.studyReviewNormalizedScore = it.studyReviewScore.toDouble() / max } + } + + private fun normalizeCitationCoefficients(studiesInfo: List) { + val citationCoefficients = studiesInfo.map { it.studyReviewCitationCoefficient!! } + val max = citationCoefficients.max() + studiesInfo.forEach { + it.studyReviewNormalizedCitationCoefficient = it.studyReviewCitationCoefficient?.div(max) + } + } + + private fun classifyNormalizedScores(studiesInfo: List) { + studiesInfo.forEach { + it.studyScoreClassification = when (it.studyReviewNormalizedScore!!) { + in 0.0..0.14 -> HazyValues.LOW + in 0.15..0.45 -> HazyValues.MEDIUM + else -> HazyValues.HIGH + } + } + } + + private fun classifyNormalizedCitationCoefficients(studiesInfo: List) { + studiesInfo.forEach { + it.studyCitationCoefficientClassification = when (it.studyReviewNormalizedCitationCoefficient!!) { + in 0.0..0.1 -> HazyValues.LOW + in 0.11..0.19 -> HazyValues.MEDIUM + else -> HazyValues.HIGH + } + } + } + + private fun suggestStudiesClassification(studiesInfo: List): List { + studiesInfo.forEach { + it.studyReviewSuggestion = when { + it.studyScoreClassification == HazyValues.HIGH + && it.studyCitationCoefficientClassification == HazyValues.HIGH + || it.studyCitationCoefficientClassification == HazyValues.MEDIUM + -> "Automatic inclusion" + + it.studyScoreClassification == HazyValues.LOW + && it.studyCitationCoefficientClassification == HazyValues.MEDIUM + || it.studyCitationCoefficientClassification == HazyValues.LOW + -> "Automatic exclusion" + + else -> "Manual review" + } + } + return studiesInfo.map { StudyStatusSuggestion(it.studyReviewId, it.studyReviewSuggestion!!) } } -} \ No newline at end of file +} From 1cd69280d5f5144c2a69ab8f65a084d4057d1c32 Mon Sep 17 00:00:00 2001 From: Shoji Date: Fri, 25 Oct 2024 16:27:57 -0300 Subject: [PATCH 003/153] feat(scas): classify studies with scas m2 values --- .../kotlin/br/ifsp/octaviano/Principal.kt | 104 +++++++++++++++++- .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 56 ++++++---- 2 files changed, 134 insertions(+), 26 deletions(-) diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt index 5759f5378..422b9121d 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -1,14 +1,108 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.* +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.StudyReviewInfo fun main() { val input = listOf( - StudyReviewInfo(1, 21, 10, 2023), - StudyReviewInfo(2, 0, 0, 2006), - StudyReviewInfo(3, 54, 40, 2023), - StudyReviewInfo(4, 34, 30, 2015), + StudyReviewInfo(1, 84, 1, 2006), + StudyReviewInfo(2, 83, 0, 2006), + StudyReviewInfo(3, 71, 1, 2006), + StudyReviewInfo(4, 59, 0, 2007), + StudyReviewInfo(5, 56, 0, 2007), + StudyReviewInfo(6, 55, 6, 2004), + StudyReviewInfo(7, 55, 10, 2006), + StudyReviewInfo(8, 55, 9, 2006), + StudyReviewInfo(9, 52, 18, 2003), + StudyReviewInfo(10, 49, 35, 2004), + StudyReviewInfo(11, 48, 2, 2006), + StudyReviewInfo(12, 45, 0, 2005), + StudyReviewInfo(13, 44, 2, 2006), + StudyReviewInfo(14, 43, 3, 2005), + StudyReviewInfo(15, 41, 0, 2006), + StudyReviewInfo(16, 40, 0, 2007), + StudyReviewInfo(17, 39, 0, 2007), + StudyReviewInfo(18, 38, 0, 2006), + StudyReviewInfo(19, 38, 7, 2005), + StudyReviewInfo(20, 38, 7, 2005), + StudyReviewInfo(21, 35, 1, 2007), + StudyReviewInfo(22, 35, 0, 2007), + StudyReviewInfo(23, 35, 0, 2007), + StudyReviewInfo(24, 34, 0, 2007), + StudyReviewInfo(25, 34, 1, 2006), + StudyReviewInfo(26, 34, 0, 2006), + StudyReviewInfo(27, 32, 0, 2007), + StudyReviewInfo(28, 32, 0, 2007), + StudyReviewInfo(29, 32, 2, 2005), + StudyReviewInfo(30, 32, 0, 2007), + StudyReviewInfo(31, 31, 1, 2004), + StudyReviewInfo(32, 31, 0, 2007), + StudyReviewInfo(33, 31, 8, 2002), + StudyReviewInfo(34, 29, 0, 2006), + StudyReviewInfo(35, 29, 0, 2006), + StudyReviewInfo(36, 29, 0, 2007), + StudyReviewInfo(37, 29, 9, 2006), + StudyReviewInfo(38, 28, 0, 2006), + StudyReviewInfo(39, 28, 0, 2007), + StudyReviewInfo(40, 27, 0, 2006), + StudyReviewInfo(41, 27, 0, 2006), + StudyReviewInfo(42, 26, 0, 2005), + StudyReviewInfo(43, 26, 4, 2005), + StudyReviewInfo(44, 25, 0, 2006), + StudyReviewInfo(45, 25, 1, 2006), + StudyReviewInfo(46, 25, 6, 2005), + StudyReviewInfo(47, 24, 0, 2007), + StudyReviewInfo(48, 23, 0, 2006), + StudyReviewInfo(49, 22, 0, 2007), + StudyReviewInfo(50, 22, 0, 2004), + StudyReviewInfo(51, 22, 3, 2006), + StudyReviewInfo(52, 22, 0, 2005), + StudyReviewInfo(53, 22, 0, 2007), + StudyReviewInfo(54, 20, 6, 2006), + StudyReviewInfo(55, 20, 1, 2004), + StudyReviewInfo(56, 20, 0, 2007), + StudyReviewInfo(57, 18, 0, 2007), + StudyReviewInfo(58, 18, 3, 2005), + StudyReviewInfo(59, 17, 0, 2003), + StudyReviewInfo(60, 17, 6, 2005), + StudyReviewInfo(61, 17, 1, 2005), + StudyReviewInfo(62, 17, 0, 2007), + StudyReviewInfo(63, 16, 0, 2006), + StudyReviewInfo(64, 16, 0, 2006), + StudyReviewInfo(65, 16, 0, 2007), + StudyReviewInfo(66, 15, 0, 2004), + StudyReviewInfo(67, 15, 0, 2000), + StudyReviewInfo(68, 15, 0, 2007), + StudyReviewInfo(69, 14, 0, 2007), + StudyReviewInfo(70, 13, 0, 2007), + StudyReviewInfo(71, 13, 5, 2005), + StudyReviewInfo(72, 13, 0, 2006), + StudyReviewInfo(73, 11, 3, 2005), + StudyReviewInfo(74, 11, 0, 2007), + StudyReviewInfo(75, 11, 0, 2007), + StudyReviewInfo(76, 11, 0, 2007), + StudyReviewInfo(77, 11, 0, 2007), + StudyReviewInfo(78, 11, 0, 2007), + StudyReviewInfo(79, 10, 0, 2006), + StudyReviewInfo(80, 10, 0, 2007), + StudyReviewInfo(81, 9, 0, 2000), + StudyReviewInfo(82, 9, 0, 2007), + StudyReviewInfo(83, 9, 0, 2006), + StudyReviewInfo(84, 9, 0, 2007), + StudyReviewInfo(85, 8, 0, 2007), + StudyReviewInfo(86, 8, 0, 2006), + StudyReviewInfo(87, 8, 0, 2006), + StudyReviewInfo(88, 8, 0, 2002), + StudyReviewInfo(89, 8, 0, 2006), + StudyReviewInfo(90, 8, 0, 2007), + StudyReviewInfo(91, 8, 0, 2003), + StudyReviewInfo(92, 6, 0, 2006), + StudyReviewInfo(93, 6, 0, 2007), + StudyReviewInfo(94, 6, 0, 2003), + StudyReviewInfo(95, 3, 0, 2006), + StudyReviewInfo(96, 3, 0, 2007), + StudyReviewInfo(97, 3, 0, 2007), ) val service: SelectionStatusSuggestionService = ScasImpl() diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt index 8d6f2e63c..9ea4bee23 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -2,6 +2,7 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService import br.all.domain.services.SelectionStatusSuggestionService.* +import java.math.RoundingMode class ScasImpl : SelectionStatusSuggestionService { private enum class HazyValues { @@ -29,6 +30,7 @@ class ScasImpl : SelectionStatusSuggestionService { calculateCitationCoefficients(studiesInfo, mostRecentYear) normalizeScores(studiesInfo) normalizeCitationCoefficients(studiesInfo) + classifyNormalizedScores(studiesInfo) classifyNormalizedCitationCoefficients(studiesInfo) val studySuggestions = suggestStudiesClassification(studiesInfo) @@ -54,60 +56,72 @@ class ScasImpl : SelectionStatusSuggestionService { ) { studiesInfo.forEach { it.studyReviewCitationCoefficient = - (1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear)) + ((1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear))).toBigDecimal().setScale(2, RoundingMode.HALF_EVEN).toDouble() } } private fun normalizeScores(studiesInfo: List) { val scores = studiesInfo.map { it.studyReviewScore } - val max = scores.max() - studiesInfo.forEach { it.studyReviewNormalizedScore = it.studyReviewScore.toDouble() / max } + val max = scores.max().toDouble() + studiesInfo.forEach { it.studyReviewNormalizedScore = (it.studyReviewScore / max).toBigDecimal().setScale(2, RoundingMode.HALF_EVEN).toDouble() + } } private fun normalizeCitationCoefficients(studiesInfo: List) { - val citationCoefficients = studiesInfo.map { it.studyReviewCitationCoefficient!! } + val citationCoefficients = studiesInfo.mapNotNull { it.studyReviewCitationCoefficient } val max = citationCoefficients.max() studiesInfo.forEach { - it.studyReviewNormalizedCitationCoefficient = it.studyReviewCitationCoefficient?.div(max) + it.studyReviewNormalizedCitationCoefficient = (it.studyReviewCitationCoefficient?.div(max))?.toBigDecimal()?.setScale(2, RoundingMode.HALF_EVEN)?.toDouble() } } private fun classifyNormalizedScores(studiesInfo: List) { studiesInfo.forEach { - it.studyScoreClassification = when (it.studyReviewNormalizedScore!!) { - in 0.0..0.14 -> HazyValues.LOW - in 0.15..0.45 -> HazyValues.MEDIUM - else -> HazyValues.HIGH + it.studyReviewNormalizedScore?.let { studyReviewNormalizedScore -> run { + it.studyScoreClassification = when { + studyReviewNormalizedScore >= 0.46 -> HazyValues.HIGH + studyReviewNormalizedScore >= 0.13 -> HazyValues.MEDIUM + else -> HazyValues.LOW + } } - } + }} } private fun classifyNormalizedCitationCoefficients(studiesInfo: List) { studiesInfo.forEach { - it.studyCitationCoefficientClassification = when (it.studyReviewNormalizedCitationCoefficient!!) { - in 0.0..0.1 -> HazyValues.LOW - in 0.11..0.19 -> HazyValues.MEDIUM - else -> HazyValues.HIGH + it.studyReviewNormalizedCitationCoefficient?.let { studyReviewNormalizedCitationCoefficient -> run { + it.studyCitationCoefficientClassification = when { + studyReviewNormalizedCitationCoefficient >= 0.395 -> HazyValues.HIGH + studyReviewNormalizedCitationCoefficient >= 0.12 -> HazyValues.MEDIUM + else -> HazyValues.LOW + } } - } + }} } private fun suggestStudiesClassification(studiesInfo: List): List { studiesInfo.forEach { it.studyReviewSuggestion = when { - it.studyScoreClassification == HazyValues.HIGH - && it.studyCitationCoefficientClassification == HazyValues.HIGH - || it.studyCitationCoefficientClassification == HazyValues.MEDIUM + (it.studyScoreClassification == HazyValues.HIGH + && (it.studyCitationCoefficientClassification == HazyValues.HIGH + || it.studyCitationCoefficientClassification == HazyValues.MEDIUM) + ) || (it.studyScoreClassification == HazyValues.MEDIUM + && it.studyCitationCoefficientClassification == HazyValues.HIGH) -> "Automatic inclusion" it.studyScoreClassification == HazyValues.LOW - && it.studyCitationCoefficientClassification == HazyValues.MEDIUM - || it.studyCitationCoefficientClassification == HazyValues.LOW + && (it.studyCitationCoefficientClassification == HazyValues.MEDIUM + || it.studyCitationCoefficientClassification == HazyValues.LOW) -> "Automatic exclusion" else -> "Manual review" } } - return studiesInfo.map { StudyStatusSuggestion(it.studyReviewId, it.studyReviewSuggestion!!) } + + return studiesInfo.mapNotNull { it.studyReviewSuggestion?.let { studyReviewSuggestion -> + StudyStatusSuggestion(it.studyReviewId, + studyReviewSuggestion + ) + } } } } From 4ab28b924881492366890ff428b02b1c8c4c8dc4 Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:10:32 -0300 Subject: [PATCH 004/153] refactor: improve deleteSearchSessionServiceImpl by adding existence check before fetching session --- .../delete/DeleteSearchSessionPresenter.kt | 4 +- .../delete/DeleteSearchSessionService.kt | 10 +++-- .../delete/DeleteSearchSessionServiceImpl.kt | 42 +++++++++++-------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt index a202c3eca..e9ef45ad2 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt @@ -1,6 +1,6 @@ package br.all.application.search.delete -import br.all.application.shared.presenter.GenericPresenter import br.all.application.search.delete.DeleteSearchSessionService.ResponseModel +import br.all.application.shared.presenter.GenericPresenter -interface DeleteSearchSessionPresenter: GenericPresenter \ No newline at end of file +interface DeleteSearchSessionPresenter : GenericPresenter diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt index 686fb3abe..2067d589a 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt @@ -1,11 +1,15 @@ +@file:Suppress("ktlint:standard:no-wildcard-imports") + package br.all.application.search.delete -import br.all.application.search.update.PatchSearchSessionPresenter import io.swagger.v3.oas.annotations.media.Schema import java.util.* interface DeleteSearchSessionService { - fun delete(presenter: DeleteSearchSessionPresenter, request: RequestModel) + fun delete( + presenter: DeleteSearchSessionPresenter, + request: RequestModel, + ) data class RequestModel( val userId: UUID, @@ -19,4 +23,4 @@ interface DeleteSearchSessionService { val systematicStudyId: UUID, val sessionId: UUID, ) -} \ No newline at end of file +} diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt index 93c25f35c..bce8b23c3 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt @@ -8,38 +8,46 @@ import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.user.CredentialsService import br.all.domain.model.review.SystematicStudy -class DeleteSearchSessionServiceImpl ( +class DeleteSearchSessionServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, ) : DeleteSearchSessionService { override fun delete( presenter: DeleteSearchSessionPresenter, - request: DeleteSearchSessionService.RequestModel + request: DeleteSearchSessionService.RequestModel, ) { val user = credentialsService.loadCredentials(request.userId)?.toUser() - - val searchSessionDto = searchSessionRepository.findById(request.sessionId) - val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) - val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val systematicStudy = + systematicStudyRepository + .findById( + request.systematicStudyId, + )?.let { + SystematicStudy.fromDto(it) + } presenter.prepareIfFailsPreconditions(user, systematicStudy) if (presenter.isDone()) return - if (searchSessionDto != null) { - searchSessionRepository.deleteById(searchSessionDto.id) - - presenter.prepareSuccessView( - DeleteSearchSessionService.ResponseModel( - userId = request.userId, - systematicStudyId = request.systematicStudyId, - sessionId = request.sessionId + if (searchSessionRepository.existsById(request.sessionId)) { + val searchSessionDto = searchSessionRepository.findById(request.sessionId) + if (searchSessionDto != null) { + searchSessionRepository.deleteById(searchSessionDto.id) + presenter.prepareSuccessView( + DeleteSearchSessionService.ResponseModel( + userId = request.userId, + systematicStudyId = request.systematicStudyId, + sessionId = request.sessionId, + ), ) - ) + } else { + val message = "There is no search session with ID ${request.sessionId}" + presenter.prepareFailView(EntityNotFoundException(message)) + } } else { val message = "There is no search session with ID ${request.sessionId}" presenter.prepareFailView(EntityNotFoundException(message)) } } -} \ No newline at end of file +} From d8538cba89b9fac79cf416ecc19126a164189a34 Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:21:03 -0300 Subject: [PATCH 005/153] test: add unit tests for deleteSearchSessionServiceImpl --- .../DeleteSearchSessionServiceImplTest.kt | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt diff --git a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt new file mode 100644 index 000000000..5050a9dc5 --- /dev/null +++ b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt @@ -0,0 +1,141 @@ +@file:Suppress("ktlint:standard:no-wildcard-imports") + +package br.all.application.search.delete + +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.search.repository.SearchSessionRepository +import br.all.application.search.util.TestDataFactory +import br.all.application.shared.exceptions.EntityNotFoundException +import br.all.application.shared.exceptions.UnauthenticatedUserException +import br.all.application.shared.exceptions.UnauthorizedUserException +import br.all.application.user.CredentialsService +import br.all.application.util.PreconditionCheckerMockingNew +import io.mockk.* +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.junit5.MockKExtension +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(MockKExtension::class) +class DeleteSearchSessionServiceImplTest { + @MockK(relaxUnitFun = true) + private lateinit var systematicStudyRepository: SystematicStudyRepository + + @MockK(relaxUnitFun = true) + private lateinit var searchSessionRepository: SearchSessionRepository + + @MockK(relaxed = true) + private lateinit var presenter: DeleteSearchSessionPresenter + + @MockK + private lateinit var credentialService: CredentialsService + + @InjectMockKs + private lateinit var sut: DeleteSearchSessionServiceImpl + + private lateinit var factory: TestDataFactory + private lateinit var preconditionCheckerMocking: PreconditionCheckerMockingNew + + @BeforeEach + fun setUp() { + factory = TestDataFactory() + preconditionCheckerMocking = + PreconditionCheckerMockingNew( + presenter, + credentialService, + systematicStudyRepository, + factory.userId, + factory.systematicStudyId, + ) + } + + @Nested + @DisplayName("When successfully deleting search session") + inner class WhenSuccessfullyDeletingSearchSession { + @BeforeEach + fun setUp() { + preconditionCheckerMocking.makeEverythingWork() + } + + @Test + fun `should successfully delete search session`() { + val request = factory.deleteRequestModel() + val response = factory.deleteResponseModel() + + every { searchSessionRepository.existsById(factory.searchSessionId) } returns true + every { searchSessionRepository.findById(factory.searchSessionId) } returns factory.generateDto() + every { searchSessionRepository.deleteById(factory.searchSessionId) } just Runs + + sut.delete(presenter, request) + + verify { + searchSessionRepository.deleteById(factory.searchSessionId) + presenter.prepareSuccessView(response) + } + } + } + + @Nested + @DisplayName("When unable to delete search session") + inner class WhenUnableToDeleteSearchSession { + @Test + fun `should fail with EntityNotFoundException when session does not exist`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeEverythingWork() + every { searchSessionRepository.existsById(factory.searchSessionId) } returns false + every { searchSessionRepository.findById(factory.searchSessionId) } returns null + + sut.delete(presenter, request) + + verify { + searchSessionRepository.existsById(factory.searchSessionId) + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should the researcher be unauthorized if they are not a collaborator`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthorized() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should prepare fail view if the researcher is unauthenticated`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthenticated() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should prepare fail view if the researcher is unauthorized`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthorized() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + } +} From 45693e08acc163e2fc648bff274ed7a03607a6ac Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:28:13 -0300 Subject: [PATCH 006/153] test: add deleteRequestModel and deleteResponseModel methods to testDataFactory --- .../search/util/TestDataFactory.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt index a574db434..3053801d0 100644 --- a/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt @@ -3,6 +3,7 @@ package br.all.application.search.util import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.PicocDto import br.all.application.protocol.repository.ProtocolDto +import br.all.application.search.delete.DeleteSearchSessionService import br.all.application.search.find.service.FindAllSearchSessionsBySourceService import br.all.application.search.find.service.FindAllSearchSessionsService import br.all.application.search.find.service.FindSearchSessionService @@ -64,6 +65,26 @@ class TestDataFactory { invalidEntries: List = emptyList() ) = CreateResponseModel(userId, systematicStudyId, sessionId, invalidEntries) + fun deleteRequestModel( + userId: UUID = this.userId, + systematicStudyId: UUID = this.systematicStudyId, + sessionId: UUID = this.searchSessionId, + ) = DeleteSearchSessionService.RequestModel( + userId, + systematicStudyId, + sessionId, + ) + + fun deleteResponseModel( + userId: UUID = this.userId, + systematicStudyId: UUID = this.systematicStudyId, + sessionId: UUID = this.searchSessionId, + ) = DeleteSearchSessionService.ResponseModel( + userId, + systematicStudyId, + sessionId, + ) + fun findOneRequestModel( userId: UUID = this.userId, systematicStudyId: UUID = this.systematicStudyId, From 922308d69c8dda2c1ebe0657dbddee36bec8e450 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 5 Mar 2025 18:43:04 -0300 Subject: [PATCH 007/153] refactor: improve logic by removing unnecessary query and inverting if clause --- .../delete/DeleteSearchSessionServiceImpl.kt | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt index bce8b23c3..9e2c3bdca 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt @@ -30,24 +30,20 @@ class DeleteSearchSessionServiceImpl( if (presenter.isDone()) return - if (searchSessionRepository.existsById(request.sessionId)) { - val searchSessionDto = searchSessionRepository.findById(request.sessionId) - if (searchSessionDto != null) { - searchSessionRepository.deleteById(searchSessionDto.id) - presenter.prepareSuccessView( - DeleteSearchSessionService.ResponseModel( - userId = request.userId, - systematicStudyId = request.systematicStudyId, - sessionId = request.sessionId, - ), - ) - } else { - val message = "There is no search session with ID ${request.sessionId}" - presenter.prepareFailView(EntityNotFoundException(message)) - } - } else { - val message = "There is no search session with ID ${request.sessionId}" - presenter.prepareFailView(EntityNotFoundException(message)) + val searchSessionDto = searchSessionRepository.findById(request.sessionId) + + if(searchSessionDto == null){ + presenter.prepareFailView(EntityNotFoundException("There is no search session with ID ${request.sessionId}")) + return } + + searchSessionRepository.deleteById(searchSessionDto.id) + presenter.prepareSuccessView( + DeleteSearchSessionService.ResponseModel( + userId = request.userId, + systematicStudyId = request.systematicStudyId, + sessionId = request.sessionId, + ), + ) } } From 22b351aca6c2099d394426950a0416e32cd36c53 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 5 Mar 2025 18:50:30 -0300 Subject: [PATCH 008/153] test: remove unused function from tests --- .../search/delete/DeleteSearchSessionServiceImplTest.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt index 5050a9dc5..265f33150 100644 --- a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt @@ -66,7 +66,6 @@ class DeleteSearchSessionServiceImplTest { val request = factory.deleteRequestModel() val response = factory.deleteResponseModel() - every { searchSessionRepository.existsById(factory.searchSessionId) } returns true every { searchSessionRepository.findById(factory.searchSessionId) } returns factory.generateDto() every { searchSessionRepository.deleteById(factory.searchSessionId) } just Runs @@ -87,13 +86,11 @@ class DeleteSearchSessionServiceImplTest { val request = factory.deleteRequestModel() preconditionCheckerMocking.makeEverythingWork() - every { searchSessionRepository.existsById(factory.searchSessionId) } returns false every { searchSessionRepository.findById(factory.searchSessionId) } returns null sut.delete(presenter, request) verify { - searchSessionRepository.existsById(factory.searchSessionId) presenter.prepareFailView(any()) presenter.isDone() } From b0d8c64607a968358560f1eb805f614eedf40e72 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 19:28:36 -0300 Subject: [PATCH 009/153] feat: create collaboration document --- .../collaboration/CollaborationDocument.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt new file mode 100644 index 000000000..f7519c32f --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt @@ -0,0 +1,14 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +import java.util.* + +@Document("collaboration") +data class CollaborationDocument( + @Id val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val status: String, + val permissions: List +) From 2c4312a2a1a64edadc3387cbbf2ff280879e0517 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 19:57:17 -0300 Subject: [PATCH 010/153] feat: create invite document --- .../infrastructure/collaboration/InviteDocument.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt new file mode 100644 index 000000000..cb53006d5 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -0,0 +1,14 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +import java.util.* + +@Document("invite") +data class InviteDocument( + @Id val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val inviteDate: Date, + val expirationDate: Date, +) From fef107e1ab794b6389cd86a7b30d031c5ab979c1 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:20:16 -0300 Subject: [PATCH 011/153] feat: define base of collaboration entity --- .../model/collaboration/Collaboration.kt | 16 ++++++++++++++ .../model/collaboration/CollaborationId.kt | 21 +++++++++++++++++++ .../collaboration/CollaborationPermission.kt | 7 +++++++ .../collaboration/CollaborationStatus.kt | 8 +++++++ .../collaboration/CollaborationDocument.kt | 2 +- 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt new file mode 100644 index 000000000..4fb768ce0 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -0,0 +1,16 @@ +package br.all.domain.model.collaboration + +import br.all.domain.model.review.SystematicStudyId +import br.all.domain.shared.ddd.Entity +import br.all.domain.user.UserAccountId +import java.util.UUID + +class Collaboration( + id: CollaborationId, + title: String, + systematicStudyId: SystematicStudyId, + userId: UserAccountId, + status: CollaborationStatus, + permissions: Set = emptySet() + ): Entity(id) { +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt new file mode 100644 index 000000000..104134f9c --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt @@ -0,0 +1,21 @@ +package br.all.domain.model.collaboration + +import br.all.domain.shared.ddd.Identifier +import br.all.domain.shared.ddd.Notification +import java.util.* + +@JvmInline +value class CollaborationId(private val value: UUID) : Identifier { + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + override fun validate() = Notification() + + override fun value() = value + + override fun toString() = value.toString() +} + +fun UUID.toCollaborationId() = CollaborationId(this) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt new file mode 100644 index 000000000..9f87ac2f9 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt @@ -0,0 +1,7 @@ +package br.all.domain.model.collaboration + +enum class CollaborationPermission { + EDIT, + REVIEW_STUDIES, + VIEW +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt new file mode 100644 index 000000000..698aa33ed --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt @@ -0,0 +1,8 @@ +package br.all.domain.model.collaboration + +enum class CollaborationStatus { + INVITED, + REFUSED, + REMOVED, + ACTIVE +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt index f7519c32f..99f6ff6b7 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt @@ -10,5 +10,5 @@ data class CollaborationDocument( val systematicStudyId: UUID, val userId: UUID, val status: String, - val permissions: List + val permissions: Set = emptySet() ) From 48d79a9014accdd6cb0cc7cb59ad8edb30dd45e5 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:20:29 -0300 Subject: [PATCH 012/153] feat: define base of invite entity --- .../all/domain/model/collaboration/Invite.kt | 15 +++++++++++++ .../domain/model/collaboration/InviteId.kt | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt new file mode 100644 index 000000000..59e038d1c --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -0,0 +1,15 @@ +package br.all.domain.model.collaboration + +import br.all.domain.model.review.SystematicStudyId +import br.all.domain.shared.ddd.Entity +import br.all.domain.user.UserAccountId +import java.util.* + +class Invite( + id: InviteId, + systematicStudyId: SystematicStudyId, + userId: UserAccountId, + inviteDate: Date, + expirationDate: Date +) : Entity(id) { +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt new file mode 100644 index 000000000..cc045b88d --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt @@ -0,0 +1,21 @@ +package br.all.domain.model.collaboration + +import br.all.domain.shared.ddd.Identifier +import br.all.domain.shared.ddd.Notification +import java.util.* + +@JvmInline +value class InviteId(private val value: UUID) : Identifier { + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + override fun validate() = Notification() + + override fun value() = value + + override fun toString() = value.toString() +} + +fun UUID.toInviteId() = InviteId(this) \ No newline at end of file From 85b06170611bb11a88ec4773b6b5de23454f87e9 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:21:51 -0300 Subject: [PATCH 013/153] feat: remove unused status values --- .../br/all/domain/model/collaboration/CollaborationStatus.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt index 698aa33ed..d48c3431c 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt @@ -1,8 +1,6 @@ package br.all.domain.model.collaboration enum class CollaborationStatus { - INVITED, - REFUSED, REMOVED, ACTIVE } \ No newline at end of file From c1e4420b3b45fb627ebefc69f05e74ee14fa62e2 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 21:27:33 -0300 Subject: [PATCH 014/153] feat: change invite dates to LocalDateTime --- .../model/collaboration/Collaboration.kt | 30 ++++++++++++++++--- .../all/domain/model/collaboration/Invite.kt | 7 +++-- .../collaboration/InviteDocument.kt | 5 ++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index 4fb768ce0..f6648ccbd 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -2,15 +2,37 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity +import br.all.domain.shared.ddd.Notification import br.all.domain.user.UserAccountId import java.util.UUID class Collaboration( id: CollaborationId, - title: String, - systematicStudyId: SystematicStudyId, - userId: UserAccountId, - status: CollaborationStatus, + val systematicStudyId: SystematicStudyId, + val userId: UserAccountId, + status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { + init{ + + } + + private val _permissions = permissions.toMutableSet() + val permissions get() = _permissions + + var status = status + private set + + fun addPermission(permission: CollaborationPermission) = _permissions.add(permission) + + fun removePermission(permission: CollaborationPermission) = _permissions.remove(permission) + + fun removeCollaboration() { + status = CollaborationStatus.REMOVED + } + + private fun validate() = Notification().also{ + if(permissions.isEmpty()) + it.addError("Collaboration must have at least one permission") + } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 59e038d1c..f9436742f 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -3,13 +3,14 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity import br.all.domain.user.UserAccountId +import java.time.LocalDateTime import java.util.* class Invite( id: InviteId, systematicStudyId: SystematicStudyId, - userId: UserAccountId, - inviteDate: Date, - expirationDate: Date + userId: UserAccountId, + inviteDate: LocalDateTime, + expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt index cb53006d5..086d2276f 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -2,6 +2,7 @@ package br.all.infrastructure.collaboration import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document +import java.time.LocalDateTime import java.util.* @Document("invite") @@ -9,6 +10,6 @@ data class InviteDocument( @Id val id: UUID, val systematicStudyId: UUID, val userId: UUID, - val inviteDate: Date, - val expirationDate: Date, + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime, ) From b80b28a7e73370530190197adb9a09a3140af013 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 21:57:33 -0300 Subject: [PATCH 015/153] feat: implement init clauses --- .../kotlin/br/all/domain/model/collaboration/Collaboration.kt | 4 +++- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index f6648ccbd..ad4e92016 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -13,8 +13,10 @@ class Collaboration( status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { + init{ - + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } } private val _permissions = permissions.toMutableSet() diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index f9436742f..fcacce0e6 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -13,4 +13,8 @@ class Invite( inviteDate: LocalDateTime, expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { + + init{ + require(expirationDate.isAfter(inviteDate)) + } } \ No newline at end of file From 2e3a634cb57504e31d570ccf0a717bb8249239d1 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 9 Apr 2025 19:57:16 -0300 Subject: [PATCH 016/153] feat: add validation to invite entity --- .../br/all/domain/model/collaboration/Invite.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index fcacce0e6..c654b0160 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -2,6 +2,7 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity +import br.all.domain.shared.ddd.Notification import br.all.domain.user.UserAccountId import java.time.LocalDateTime import java.util.* @@ -10,11 +11,17 @@ class Invite( id: InviteId, systematicStudyId: SystematicStudyId, userId: UserAccountId, - inviteDate: LocalDateTime, - expirationDate: LocalDateTime = inviteDate.plusDays(30) + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { - - init{ - require(expirationDate.isAfter(inviteDate)) + + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + fun validate() = Notification().also { + if (inviteDate.isAfter(expirationDate)) + it.addError("Invite date cannot be after expiration date") } } \ No newline at end of file From 8ccd714cec1a15e3e252e31d0eb0fae00ef3e02d Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 9 Apr 2025 21:33:58 -0300 Subject: [PATCH 017/153] feat: create collaboration repository and its implementation --- .../repository/CollaborationDto.kt | 11 +++++ .../repository/CollaborationRepository.kt | 11 +++++ .../collaboration/repository/InviteDto.kt | 12 +++++ .../collaboration/repository/InviteMapper.kt | 2 + .../all/domain/model/collaboration/Invite.kt | 4 +- .../CollaborationRepositoryImpl.kt | 45 +++++++++++++++++++ .../MongoCollaborationRepository.kt | 6 +++ .../collaboration/MongoInviteRepository.kt | 6 +++ 8 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt new file mode 100644 index 000000000..34a74c3f9 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt @@ -0,0 +1,11 @@ +package br.all.application.collaboration.repository + +import java.util.* + +class CollaborationDto ( + val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val status: String, + val permissions: Set +) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt new file mode 100644 index 000000000..7896877dd --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt @@ -0,0 +1,11 @@ +package br.all.application.collaboration.repository + +import java.util.* + +interface CollaborationRepository { + fun saveOrUpdateCollaboration(dto: CollaborationDto) + fun saveOrUpdateInvite(dto: InviteDto) + + fun listAllCollaborationsBySystematicStudyId(id: UUID): List + fun listAllInvitesBySystematicStudyId(id: UUID): List +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt new file mode 100644 index 000000000..609610c03 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt @@ -0,0 +1,12 @@ +package br.all.application.collaboration.repository + +import java.time.LocalDateTime +import java.util.* + +class InviteDto ( + val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime +) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt new file mode 100644 index 000000000..2cf3ede6f --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt @@ -0,0 +1,2 @@ +package br.all.application.collaboration.repository + diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index c654b0160..931280ee6 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -9,8 +9,8 @@ import java.util.* class Invite( id: InviteId, - systematicStudyId: SystematicStudyId, - userId: UserAccountId, + val systematicStudyId: SystematicStudyId, + val userId: UserAccountId, val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt new file mode 100644 index 000000000..664db2977 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -0,0 +1,45 @@ +package br.all.infrastructure.collaboration + +import br.all.application.collaboration.repository.CollaborationDto +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.InviteDto +import java.util.* + +class CollaborationRepositoryImpl( + private val innerCollaborationRepository: MongoCollaborationRepository, + private val innerInviteRepository: MongoInviteRepository +) + : CollaborationRepository +{ + override fun saveOrUpdateCollaboration(dto: CollaborationDto) { + innerCollaborationRepository.save(CollaborationDocument( + dto.id, + dto.systematicStudyId, + dto.userId, + dto.status, + dto.permissions + )) + } + + override fun saveOrUpdateInvite(dto: InviteDto) { + innerInviteRepository.save(InviteDocument( + dto.id, + dto.systematicStudyId, + dto.userId, + dto.inviteDate, + dto.expirationDate + )) + } + + override fun listAllCollaborationsBySystematicStudyId(id: UUID): List { + return innerCollaborationRepository.findAll().filter { it.systematicStudyId == id }.map { + CollaborationDto(it.id, it.systematicStudyId, it.userId, it.status, it.permissions) + } + } + + override fun listAllInvitesBySystematicStudyId(id: UUID): List { + return innerInviteRepository.findAll().filter { it.systematicStudyId == id }.map { + InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate) + } + } +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt new file mode 100644 index 000000000..043e6c494 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt @@ -0,0 +1,6 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.mongodb.repository.MongoRepository +import java.util.* + +interface MongoCollaborationRepository: MongoRepository \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt new file mode 100644 index 000000000..05358d9fe --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt @@ -0,0 +1,6 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.mongodb.repository.MongoRepository +import java.util.* + +interface MongoInviteRepository: MongoRepository \ No newline at end of file From fed8021e9cb96efc3e27e440c44801017d7ea233 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:06:20 -0300 Subject: [PATCH 018/153] feat: reimplement exception handler using existing exception mapper --- .../kotlin/br/all/shared/error/ApiExceptionHandler.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt index 8d86cb6a1..ee74206d8 100644 --- a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt +++ b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt @@ -9,10 +9,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler @ControllerAdvice class ApiExceptionHandler { - @ExceptionHandler(value = [IllegalArgumentException::class]) - fun handleIllegalArgumentException(e: IllegalArgumentException): ResponseEntity<*> { - val status = HttpStatus.BAD_REQUEST - val apiException = ErrorMessage(status, e) - return ResponseEntity(apiException, status) + @ExceptionHandler(value = [RuntimeException::class]) + fun handleRuntimeException(exception: RuntimeException): ResponseEntity<*> { + return createErrorResponseFrom(throwable = exception) } } \ No newline at end of file From 66f039eabd7b744823547d24cafdd0776d17fd44 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:07:05 -0300 Subject: [PATCH 019/153] feat: change userId to use ResearcherId --- .../br/all/domain/model/collaboration/Collaboration.kt | 6 +++--- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index ad4e92016..cc11c61e0 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -1,15 +1,15 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId +import br.all.domain.model.user.ResearcherId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification -import br.all.domain.user.UserAccountId -import java.util.UUID +import java.util.* class Collaboration( id: CollaborationId, val systematicStudyId: SystematicStudyId, - val userId: UserAccountId, + val userId: ResearcherId, status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 931280ee6..67d23d287 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -1,16 +1,16 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId +import br.all.domain.model.user.ResearcherId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification -import br.all.domain.user.UserAccountId import java.time.LocalDateTime import java.util.* class Invite( id: InviteId, val systematicStudyId: SystematicStudyId, - val userId: UserAccountId, + val userId: ResearcherId, val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { From f5f09f10c99ab500a4ce8f3e20b9f8bb55a5ab3a Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:07:30 -0300 Subject: [PATCH 020/153] feat: change SystematicStudy collaborator ids to CollaborationId --- .../collaboration/repository/InviteMapper.kt | 2 -- .../domain/model/review/SystematicStudy.kt | 24 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt deleted file mode 100644 index 2cf3ede6f..000000000 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt +++ /dev/null @@ -1,2 +0,0 @@ -package br.all.application.collaboration.repository - diff --git a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt index 6ff248e6e..f4efb9c97 100644 --- a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt +++ b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt @@ -1,6 +1,6 @@ package br.all.domain.model.review -import br.all.domain.model.user.ResearcherId +import br.all.domain.model.collaboration.CollaborationId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification import br.all.domain.shared.utils.exists @@ -10,8 +10,8 @@ class SystematicStudy( id: SystematicStudyId, title: String, description: String, - owner: ResearcherId, - collaborators: Set = emptySet(), + owner: CollaborationId, + collaborators: Set = emptySet(), ) : Entity(id) { private val _collaborators = collaborators.toMutableSet() @@ -42,19 +42,19 @@ class SystematicStudy( it.addError("Systematic Study description must not be blank!") } - fun addCollaborator(researcherId: ResearcherId) = _collaborators.add(researcherId) + fun addCollaborator(collaborationId: CollaborationId) = _collaborators.add(collaborationId) - fun changeOwner(researcherId: ResearcherId) { - _collaborators.add(researcherId) - owner = researcherId + fun changeOwner(collaborationId: CollaborationId) { + _collaborators.add(collaborationId) + owner = collaborationId } - fun removeCollaborator(researcherId: ResearcherId) { - check(researcherId != owner) { "Cannot remove the Systematic Study owner: $owner" } - exists(researcherId in _collaborators) { - "Cannot remove member that is not part of the collaboration: $researcherId" + fun removeCollaborator(collaborationId: CollaborationId) { + check(collaborationId != owner) { "Cannot remove the Systematic Study owner: $owner" } + exists(collaborationId in _collaborators) { + "Cannot remove member that is not part of the collaboration: $collaborationId" } - _collaborators.remove(researcherId) + _collaborators.remove(collaborationId) } override fun toString() = "SystematicStudy(reviewId=$id, title='$title', description='$description', owner=$owner," + From 05f42295f18d18860d20e683f5f0a2bd8988aad6 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:08:04 -0300 Subject: [PATCH 021/153] feat: implement mapper for collaboration entities and dtos --- .../repository/CollaborationMapper.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt new file mode 100644 index 000000000..f81fcd274 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt @@ -0,0 +1,37 @@ +package br.all.application.collaboration.repository + +import br.all.domain.model.collaboration.* +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId + +fun Invite.toDto(): InviteDto = InviteDto( + id = this.id.value(), + systematicStudyId = this.systematicStudyId.value(), + userId = this.userId.value, + inviteDate = this.inviteDate, + expirationDate = this.expirationDate +) + +fun InviteDto.toDomain(): Invite = Invite( + id = this.id.toInviteId(), + systematicStudyId = this.systematicStudyId.toSystematicStudyId(), + userId = this.userId.toResearcherId(), + inviteDate = this.inviteDate, + expirationDate = this.expirationDate +) + +fun Collaboration.toDto(): CollaborationDto = CollaborationDto( + id = this.id.value(), + systematicStudyId = this.systematicStudyId.value(), + userId = this.userId.value, + status = this.status.name, + permissions = this.permissions.map { it.name }.toSet() +) + +fun CollaborationDto.toDomain(): Collaboration = Collaboration( + id = this.id.toCollaborationId(), + systematicStudyId = this.systematicStudyId.toSystematicStudyId(), + userId = this.userId.toResearcherId(), + status = CollaborationStatus.valueOf(this.status), + permissions = this.permissions.map { CollaborationPermission.valueOf(it) }.toSet() +) \ No newline at end of file From f3f459b1e8e0da84429f2c3cfffbd0ac88a7b26d Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:08:21 -0300 Subject: [PATCH 022/153] feat: create and implement CreateInviteService --- .../create/CreateInvitePresenter.kt | 5 ++ .../create/CreateInviteService.kt | 18 +++++++ .../create/CreateInviteServiceImpl.kt | 51 +++++++++++++++++++ .../all/shared/error/ApiExceptionHandler.kt | 1 - 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt new file mode 100644 index 000000000..9c98ea82c --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt @@ -0,0 +1,5 @@ +package br.all.application.collaboration.create + +import br.all.application.shared.presenter.GenericPresenter + +interface CreateInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt new file mode 100644 index 000000000..425e83802 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt @@ -0,0 +1,18 @@ +package br.all.application.collaboration.create + +import java.util.* + +interface CreateInviteService { + fun createInvite(presenter: CreateInvitePresenter, request: RequestModel) + + data class RequestModel( + val systematicStudyId: UUID, + val userId: UUID, + val inviteeId: UUID, + val permissions: Set + ) + + data class ResponseModel( + val inviteId: UUID + ) +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt new file mode 100644 index 000000000..f6bbd258f --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -0,0 +1,51 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDto +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.Invite +import br.all.domain.model.collaboration.toInviteId +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId +import java.time.LocalDateTime +import java.util.* + +class CreateInviteServiceImpl( + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository +) : CreateInviteService +{ + override fun createInvite(presenter: CreateInvitePresenter, request: CreateInviteService.RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + + if(presenter.isDone()) return + + if(systematicStudy!!.collaborators.any { it.value() == request.inviteeId }) { + presenter.prepareFailView( + IllegalArgumentException("User who is already a collaborator may not be invited") + ) + } + + val inviteId = UUID.randomUUID() + val invite = Invite( + inviteId.toInviteId(), + request.systematicStudyId.toSystematicStudyId(), + request.userId.toResearcherId(), + LocalDateTime.now() + ) + + collaborationRepository.saveOrUpdateInvite(invite.toDto()) + + presenter.prepareSuccessView(CreateInviteService.ResponseModel(inviteId)) + } +} \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt index ee74206d8..5ff8d72cd 100644 --- a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt +++ b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt @@ -1,6 +1,5 @@ package br.all.shared.error -import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler From e5293f33909ff64095f7c43a39d65bd7d0f73de2 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 22:16:08 -0300 Subject: [PATCH 023/153] feat: add permissions to invite --- .../collaboration/create/CreateInviteServiceImpl.kt | 4 +++- .../collaboration/repository/CollaborationMapper.kt | 4 +++- .../br/all/application/collaboration/repository/InviteDto.kt | 3 ++- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++++ .../br/all/infrastructure/collaboration/InviteDocument.kt | 3 ++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt index f6bbd258f..f72371ae0 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -6,6 +6,7 @@ import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.CollaborationPermission import br.all.domain.model.collaboration.Invite import br.all.domain.model.collaboration.toInviteId import br.all.domain.model.review.SystematicStudy @@ -41,7 +42,8 @@ class CreateInviteServiceImpl( inviteId.toInviteId(), request.systematicStudyId.toSystematicStudyId(), request.userId.toResearcherId(), - LocalDateTime.now() + request.permissions.map { CollaborationPermission.valueOf(it) }.toSet(), + inviteDate = LocalDateTime.now(), ) collaborationRepository.saveOrUpdateInvite(invite.toDto()) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt index f81fcd274..b7e2fc168 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt @@ -9,13 +9,15 @@ fun Invite.toDto(): InviteDto = InviteDto( systematicStudyId = this.systematicStudyId.value(), userId = this.userId.value, inviteDate = this.inviteDate, - expirationDate = this.expirationDate + expirationDate = this.expirationDate, + permissions = this.permissions.map { it.name }.toSet() ) fun InviteDto.toDomain(): Invite = Invite( id = this.id.toInviteId(), systematicStudyId = this.systematicStudyId.toSystematicStudyId(), userId = this.userId.toResearcherId(), + permissions = this.permissions.map { CollaborationPermission.valueOf(it) }.toSet(), inviteDate = this.inviteDate, expirationDate = this.expirationDate ) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt index 609610c03..2ebf7cc41 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt @@ -8,5 +8,6 @@ class InviteDto ( val systematicStudyId: UUID, val userId: UUID, val inviteDate: LocalDateTime, - val expirationDate: LocalDateTime + val expirationDate: LocalDateTime, + val permissions: Set ) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 67d23d287..b2bb0983d 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -11,10 +11,14 @@ class Invite( id: InviteId, val systematicStudyId: SystematicStudyId, val userId: ResearcherId, + permissions: Set = emptySet(), val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { + private val _permissions = permissions.toMutableSet() + val permissions get() = _permissions + init { val notification = validate() require(notification.hasNoErrors()) { notification.message() } diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt index 086d2276f..3f5b2626e 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -11,5 +11,6 @@ data class InviteDocument( val systematicStudyId: UUID, val userId: UUID, val inviteDate: LocalDateTime, - val expirationDate: LocalDateTime, + val expirationDate: LocalDateTime, + val permissions: Set = emptySet() ) From 1279af763d4761b2b6254e646c8cd70cfce29d3a Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:10:31 -0300 Subject: [PATCH 024/153] feat: implement delete for invites --- .../repository/CollaborationRepository.kt | 2 ++ .../collaboration/CollaborationRepositoryImpl.kt | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt index 7896877dd..70b1dd4ed 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt @@ -8,4 +8,6 @@ interface CollaborationRepository { fun listAllCollaborationsBySystematicStudyId(id: UUID): List fun listAllInvitesBySystematicStudyId(id: UUID): List + + fun deleteInvite(id: UUID) } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt index 664db2977..2fcf188d8 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -3,6 +3,7 @@ package br.all.infrastructure.collaboration import br.all.application.collaboration.repository.CollaborationDto import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.collaboration.repository.InviteDto +import java.time.LocalDateTime import java.util.* class CollaborationRepositoryImpl( @@ -38,8 +39,14 @@ class CollaborationRepositoryImpl( } override fun listAllInvitesBySystematicStudyId(id: UUID): List { - return innerInviteRepository.findAll().filter { it.systematicStudyId == id }.map { - InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate) + return innerInviteRepository.findAll() + .filter { it.systematicStudyId == id && it.expirationDate.isBefore(LocalDateTime.now()) } + .map { + InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate, it.permissions) } } + + override fun deleteInvite(id: UUID) { + innerInviteRepository.deleteById(id) + } } \ No newline at end of file From ccef3dbdbe4bb3e45edbb2c3224aad96e025818f Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:42:15 -0300 Subject: [PATCH 025/153] feat: implement accept invite service --- .../create/AcceptInvitePresenter.kt | 6 ++ .../create/AcceptInviteService.kt | 17 ++++++ .../create/AcceptInviteServiceImpl.kt | 58 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt new file mode 100644 index 000000000..96a88cf71 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.create.AcceptInviteService.ResponseModel +import br.all.application.shared.presenter.GenericPresenter + +interface AcceptInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt new file mode 100644 index 000000000..d4d780f0d --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt @@ -0,0 +1,17 @@ +package br.all.application.collaboration.create + +import java.util.* + +interface AcceptInviteService { + fun acceptInvite(presenter: AcceptInvitePresenter, request: RequestModel) + + data class RequestModel( + val systematicStudyId: UUID, + val userId: UUID, + val inviteId: UUID, + ) + + data class ResponseModel( + val collaborationId: UUID + ) +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt new file mode 100644 index 000000000..50d981ceb --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt @@ -0,0 +1,58 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDto +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.Collaboration +import br.all.domain.model.collaboration.CollaborationPermission +import br.all.domain.model.collaboration.toCollaborationId +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId +import java.util.UUID + +class AcceptInviteServiceImpl( + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository +) : AcceptInviteService { + override fun acceptInvite(presenter: AcceptInvitePresenter, request: AcceptInviteService.RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + + if(presenter.isDone()) return + + if(systematicStudy!!.collaborators.any { it.value() == request.userId }) { + presenter.prepareFailView( + IllegalArgumentException("User is already a collaborator") + ) + return + } + + val allInvites = collaborationRepository.listAllInvitesBySystematicStudyId(request.systematicStudyId) + val userInvite = allInvites.firstOrNull { it.userId == request.userId } + + if(userInvite == null) { + presenter.prepareFailView(IllegalArgumentException("User has not been invited")) + return + } + + val collaborationId = UUID.randomUUID() + val collaboration = Collaboration( + collaborationId.toCollaborationId(), + request.systematicStudyId.toSystematicStudyId(), + request.userId.toResearcherId(), + permissions = userInvite.permissions.map { CollaborationPermission.valueOf(it) }.toSet() + ) + + collaborationRepository.saveOrUpdateCollaboration(collaboration.toDto()) + presenter.prepareSuccessView(AcceptInviteService.ResponseModel(collaborationId)) + } +} \ No newline at end of file From aee33d89e063a3078cbf6af2831a9aa7033e00e3 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:42:38 -0300 Subject: [PATCH 026/153] feat: add check for user that has already been invited --- .../collaboration/create/CreateInvitePresenter.kt | 3 ++- .../collaboration/create/CreateInviteServiceImpl.kt | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt index 9c98ea82c..6863ee42d 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt @@ -1,5 +1,6 @@ package br.all.application.collaboration.create +import br.all.application.collaboration.create.CreateInviteService.ResponseModel import br.all.application.shared.presenter.GenericPresenter -interface CreateInvitePresenter : GenericPresenter \ No newline at end of file +interface CreateInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt index f72371ae0..68ad8fd75 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -37,6 +37,13 @@ class CreateInviteServiceImpl( ) } + val allInvites = collaborationRepository.listAllInvitesBySystematicStudyId(request.systematicStudyId) + if(allInvites.any { it.userId == request.inviteeId }) { + presenter.prepareFailView( + IllegalArgumentException("User who is already invited may not be invited again") + ) + } + val inviteId = UUID.randomUUID() val invite = Invite( inviteId.toInviteId(), From 2f5e60240ca082c677f8ba8b46971bb90c5645ff Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:36 -0300 Subject: [PATCH 027/153] fix: remove incorrectly typed and unused variables from systematic study --- .../review/create/CreateSystematicStudyService.kt | 1 - .../application/review/repository/SystematicStudyMapper.kt | 7 ++++--- .../br/all/domain/model/collaboration/CollaborationId.kt | 2 +- web/src/main/kotlin/br/all/review/requests/PostRequest.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt index 1b3ec80e4..44388d8e3 100644 --- a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt +++ b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt @@ -9,7 +9,6 @@ interface CreateSystematicStudyService { val userId: UUID, val title : String, val description : String, - val collaborators : Set, ) data class ResponseModel( diff --git a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt index 961dbc4e3..462508aa0 100644 --- a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt +++ b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt @@ -1,6 +1,7 @@ package br.all.application.review.repository import br.all.application.review.create.CreateSystematicStudyService.RequestModel +import br.all.domain.model.collaboration.CollaborationId import br.all.domain.model.user.ResearcherId import br.all.domain.model.review.SystematicStudy import br.all.domain.model.review.SystematicStudyId @@ -18,15 +19,15 @@ fun SystematicStudy.Companion.fromRequestModel(id: UUID, requestModel: RequestMo SystematicStudyId(id), requestModel.title, requestModel.description, - ResearcherId(requestModel.userId), + CollaborationId(requestModel.userId), ) fun SystematicStudy.Companion.fromDto(dto: SystematicStudyDto) = SystematicStudy( SystematicStudyId(dto.id), dto.title, dto.description, - ResearcherId(dto.owner), + CollaborationId(dto.owner), dto.collaborators - .map { ResearcherId(it) } + .map { CollaborationId(it) } .toMutableSet(), ) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt index 104134f9c..da15c73e1 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt @@ -5,7 +5,7 @@ import br.all.domain.shared.ddd.Notification import java.util.* @JvmInline -value class CollaborationId(private val value: UUID) : Identifier { +value class CollaborationId(val value: UUID) : Identifier { init { val notification = validate() require(notification.hasNoErrors()) { notification.message() } diff --git a/web/src/main/kotlin/br/all/review/requests/PostRequest.kt b/web/src/main/kotlin/br/all/review/requests/PostRequest.kt index b617549f6..9f66aca77 100644 --- a/web/src/main/kotlin/br/all/review/requests/PostRequest.kt +++ b/web/src/main/kotlin/br/all/review/requests/PostRequest.kt @@ -9,5 +9,5 @@ data class PostRequest( val collaborators: Set, ) { fun toCreateRequestModel(userId: UUID) = - RequestModel(userId, title, description, collaborators) + RequestModel(userId, title, description) } \ No newline at end of file From d264af89b012cc1263710b772dba87d4e6b477f8 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:48 -0300 Subject: [PATCH 028/153] feat: implement RestfulAcceptInvitePresenter --- .../presenter/RestfulAcceptInvitePresenter.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt diff --git a/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt new file mode 100644 index 000000000..a86487f50 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt @@ -0,0 +1,30 @@ +package br.all.collaboration.presenter + +import br.all.application.collaboration.create.AcceptInvitePresenter +import br.all.application.collaboration.create.AcceptInviteService +import br.all.application.collaboration.create.CreateInvitePresenter +import br.all.application.collaboration.create.CreateInviteService +import br.all.shared.error.createErrorResponseFrom +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.* + +class RestfulAcceptInvitePresenter : AcceptInvitePresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: AcceptInviteService.ResponseModel) { + responseEntity = ResponseEntity.status(HttpStatus.CREATED).body(ViewModel(response.collaborationId)) + } + + override fun prepareFailView(throwable: Throwable) { + responseEntity = createErrorResponseFrom(throwable) + } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val collaborationId: UUID, + ) : RepresentationModel() + +} \ No newline at end of file From 7a1fc056f2ceae0ea8516f05f5bce1d2df896dba Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:54 -0300 Subject: [PATCH 029/153] feat: implement RestfulAcceptInvitePresenter --- .../presenter/RestfulCreateInvitePresenter.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt diff --git a/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt new file mode 100644 index 000000000..aac75f54b --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt @@ -0,0 +1,28 @@ +package br.all.collaboration.presenter + +import br.all.application.collaboration.create.CreateInvitePresenter +import br.all.application.collaboration.create.CreateInviteService +import br.all.shared.error.createErrorResponseFrom +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.* + +class RestfulCreateInvitePresenter : CreateInvitePresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: CreateInviteService.ResponseModel) { + responseEntity = ResponseEntity.status(HttpStatus.CREATED).body(ViewModel(response.inviteId)) + } + + override fun prepareFailView(throwable: Throwable) { + responseEntity = createErrorResponseFrom(throwable) + } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val inviteId: UUID, + ) : RepresentationModel() + +} \ No newline at end of file From acd98ed59891004e62f886d2f03fd3a1406bcd08 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:31:20 -0300 Subject: [PATCH 030/153] feat: create beans for collaboration services --- .../CollaborationRepositoryImpl.kt | 2 ++ .../CollaborationServicesConfiguration.kt | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt index 2fcf188d8..4f6152b38 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -3,9 +3,11 @@ package br.all.infrastructure.collaboration import br.all.application.collaboration.repository.CollaborationDto import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.collaboration.repository.InviteDto +import org.springframework.stereotype.Repository import java.time.LocalDateTime import java.util.* +@Repository class CollaborationRepositoryImpl( private val innerCollaborationRepository: MongoCollaborationRepository, private val innerInviteRepository: MongoInviteRepository diff --git a/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt new file mode 100644 index 000000000..6f1536a57 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt @@ -0,0 +1,31 @@ +package br.all.collaboration.controller + +import br.all.application.collaboration.create.AcceptInviteServiceImpl +import br.all.application.collaboration.create.CreateInviteServiceImpl +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.user.CredentialsService +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class CollaborationServicesConfiguration { + + @Bean + fun createInviteService( + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository + ) = CreateInviteServiceImpl( + systematicStudyRepository, credentialsService, collaborationRepository + ) + + @Bean + fun acceptInviteService( + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository + ) = AcceptInviteServiceImpl( + systematicStudyRepository, credentialsService, collaborationRepository + ) +} \ No newline at end of file From bbde64ad01e69b5a9b04e14d484280440a7d7bfc Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 22:05:10 -0300 Subject: [PATCH 031/153] feat: create endpoints for invites --- .../controller/CollaborationController.kt | 57 +++++++++++++++++++ .../requests/PostInviteRequest.kt | 8 +++ 2 files changed, 65 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt create mode 100644 web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt diff --git a/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt new file mode 100644 index 000000000..f171f0955 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt @@ -0,0 +1,57 @@ +package br.all.collaboration.controller + +import br.all.application.collaboration.create.AcceptInviteService +import br.all.application.collaboration.create.CreateInviteService +import br.all.collaboration.presenter.RestfulAcceptInvitePresenter +import br.all.collaboration.presenter.RestfulCreateInvitePresenter +import br.all.collaboration.requests.PostInviteRequest +import br.all.security.service.AuthenticationInfoService +import io.swagger.v3.oas.annotations.Operation +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api/v1/systematic-study/{systematicStudy}") +class CollaborationController( + private val createInviteService: CreateInviteService, + private val acceptInviteService: AcceptInviteService, + private val authenticationInfoService: AuthenticationInfoService, + ) { + + @PostMapping("/invite") + @Operation(summary = "Invite an user in a systematic study") + fun createInvite( + @PathVariable systematicStudy: UUID, + @RequestBody postRequest: PostInviteRequest + ): ResponseEntity<*> { + val presenter = RestfulCreateInvitePresenter() + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = CreateInviteService.RequestModel( + systematicStudy, + userId, + postRequest.inviteeId, + postRequest.permissions.toSet() + ) + createInviteService.createInvite(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } + + @PostMapping("/invite/{inviteId}/accept") + @Operation(summary = "Invite an user in a systematic study") + fun acceptInvite( + @PathVariable systematicStudy: UUID, + @PathVariable inviteId: UUID + ): ResponseEntity<*> { + val presenter = RestfulAcceptInvitePresenter() + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = AcceptInviteService.RequestModel( + systematicStudy, + userId, + inviteId + ) + acceptInviteService.acceptInvite(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } +} \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt b/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt new file mode 100644 index 000000000..ad12991af --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt @@ -0,0 +1,8 @@ +package br.all.collaboration.requests + +import java.util.UUID + +data class PostInviteRequest( + val inviteeId: UUID, + val permissions: List +) From 603d361d4b08cb6a3ba4860fe07e86165efe5eb5 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Tue, 3 Jun 2025 11:47:59 -0300 Subject: [PATCH 032/153] build: fix kotlin version and update executions tag usage --- account/pom.xml | 18 ++---------------- pom.xml | 29 +++++++++++++++-------------- web/pom.xml | 2 +- 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/account/pom.xml b/account/pom.xml index 34e1db50c..5ae3d627f 100644 --- a/account/pom.xml +++ b/account/pom.xml @@ -30,22 +30,7 @@ org.jetbrains.kotlin kotlin-maven-plugin - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - + true maven-surefire-plugin @@ -72,6 +57,7 @@ org.postgresql postgresql + 42.7.2 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0fba64dbb..4585c5d8a 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ UTF-8 official 1.8 + 1.9.0 @@ -46,18 +47,19 @@ org.jetbrains.kotlin kotlin-reflect + ${kotlin.version} compile org.jetbrains.kotlin kotlin-stdlib - 1.9.0 + ${kotlin.version} compile org.jetbrains.kotlin kotlin-test-junit5 - 1.9.0 + ${kotlin.version} test @@ -80,7 +82,7 @@ org.jetbrains.kotlin kotlin-test-junit - 1.9.0 + ${kotlin.version} test @@ -108,24 +110,20 @@ org.jetbrains.kotlin kotlin-maven-plugin - 1.9.0 + ${kotlin.version} - - org.mapstruct - mapstruct-processor - 1.4.2.Final - org.jetbrains.kotlin kotlin-maven-allopen - 2.0.0-RC1 + ${kotlin.version} org.jetbrains.kotlin kotlin-maven-noarg - 2.0.0-RC1 + ${kotlin.version} + + true spring jpa - - spring - diff --git a/web/pom.xml b/web/pom.xml index 4d14b3ac6..f8203f80e 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -18,7 +18,7 @@ 17 - 1.8.22 + 1.9.0 From 33ae8821b5d30bdb93817e255288c553ab07c86b Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Tue, 3 Jun 2025 12:50:55 -0300 Subject: [PATCH 033/153] build: enable actions file --- .github/workflows/{ci.yml.disabled => ci.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{ci.yml.disabled => ci.yml} (100%) diff --git a/.github/workflows/ci.yml.disabled b/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/ci.yml.disabled rename to .github/workflows/ci.yml From 97e2c8ed60f695aa811c5170e264e2d1db1feb5c Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Tue, 3 Jun 2025 12:51:39 -0300 Subject: [PATCH 034/153] test: use fixed data instead of faker generation --- .../br/all/protocol/controller/ProtocolControllerTest.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt index 317efff83..79d9a3e01 100644 --- a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt +++ b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt @@ -1,5 +1,6 @@ package br.all.protocol.controller +import br.all.application.protocol.repository.CriterionDto import br.all.infrastructure.protocol.MongoProtocolRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.infrastructure.review.SystematicStudyDocument @@ -153,7 +154,11 @@ class ProtocolControllerTest( @Test fun `should update an existing protocol without deleting existing collection-type variables`() { - val document = factory.createProtocolDocument() + val document = factory.createProtocolDocument( + keywords = setOf("keyword1", "keyword2"), + robQuestions = setOf(UUID.randomUUID(), UUID.randomUUID()), + selectionCriteria = setOf(CriterionDto("desc", "INCLUSION")) + ) val json = factory.validPutRequest() protocolRepository.save(document) From 3799557a2fe7166aa8b89f01cd461f7737a5d430 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Tue, 3 Jun 2025 15:22:30 -0300 Subject: [PATCH 035/153] =?UTF-8?q?build:=20git=20r=C3=A3bi=20action?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b96aca1da..733eec78e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI with Maven 2025 on: push: - branches: [ "main" ] + branches: [ "fix-pom" ] pull_request: branches: [ "main" ] From b2231c903e8fa0cfcbdcde6f65f6d08b404d1213 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Tue, 3 Jun 2025 15:25:42 -0300 Subject: [PATCH 036/153] =?UTF-8?q?commit=20jo=C3=A3o=20txt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test-actions.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test-actions.txt b/test-actions.txt index af8ea0e99..0d133db18 100644 --- a/test-actions.txt +++ b/test-actions.txt @@ -1,2 +1 @@ -this is test push -testing push 2 \ No newline at end of file +joão \ No newline at end of file From 4e05114e6d01192b05e363f61834607b5ccbe359 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Tue, 3 Jun 2025 15:54:56 -0300 Subject: [PATCH 037/153] build: test gitattributes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..03085867b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.bib linguist-generated From dfe945861b82d0e4bf62a6ddeeae2ed77ab013cf Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 4 Jun 2025 12:28:50 -0300 Subject: [PATCH 038/153] test: remove unused internal keyword from class --- .../src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt | 2 +- review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt index 29153d030..c216b0c64 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt @@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.util.* -internal class ProtocolIdTest{ +class ProtocolIdTest{ @Test fun `valid ProtocolId`() { val uuid = UUID.randomUUID() diff --git a/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt b/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt index ac3109ab1..32234cf89 100644 --- a/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt @@ -9,7 +9,7 @@ import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue -internal class DOITest { +class DOITest { @Test fun `valid DOI should not throw an exception`() { assertDoesNotThrow { DOI("10.1590/1089-6891v16i428131") } From 9257c7c8059304b30abc6fe0005773f871599a8d Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 4 Jun 2025 13:15:19 -0300 Subject: [PATCH 039/153] test: add tags to tests that were missing --- .../src/test/kotlin/br/all/domain/user/UserAccountTest.kt | 2 ++ .../search/create/CreateSearchSessionServiceImplTest.kt | 6 ++++-- .../find/FindAllSearchSessionsBySourceServiceImplTest.kt | 3 +++ .../search/find/FindAllSearchSessionsServiceImplTest.kt | 3 +++ .../search/find/FindSearchSessionServiceImplTest.kt | 3 +++ .../search/update/UpdateSearchSessionServiceImplTest.kt | 3 +++ .../application/shared/presenter/PreconditionCheckerTest.kt | 2 ++ .../src/test/kotlin/br/all/architecture/DomainModuleTest.kt | 3 ++- .../kotlin/br/all/domain/model/search/SearchSessionTest.kt | 2 ++ review/src/test/kotlin/br/all/domain/model/study/DoiTest.kt | 2 ++ .../kotlin/br/all/domain/model/study/StudyReviewTest.kt | 2 ++ .../br/all/domain/services/BibtexConverterServiceTest.kt | 2 ++ .../br/all/domain/services/ConverterFactoryServiceTest.kt | 3 +++ .../br/all/domain/services/ReviewSimilarityServiceTest.kt | 1 + .../br/all/domain/services/RisConverterServiceTest.kt | 2 ++ .../br/all/domain/services/ScoreCalculatorServiceTest.kt | 1 + .../src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt | 2 ++ .../src/test/kotlin/br/all/domain/shared/ddd/EntityTest.kt | 3 +++ .../test/kotlin/br/all/domain/shared/ddd/LanguageTest.kt | 2 ++ .../kotlin/br/all/domain/shared/ddd/NotificationTest.kt | 2 ++ .../test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt | 2 ++ review/src/test/kotlin/br/all/domain/shared/ddd/TextTest.kt | 1 + .../src/test/kotlin/br/all/domain/shared/utils/DOITest.kt | 2 ++ .../test/kotlin/br/all/domain/shared/utils/PhraseTest.kt | 2 ++ .../br/all/infrastructure/ProtocolRepositoryImplTest.kt | 4 ++-- .../br/all/protocol/controller/ProtocolControllerTest.kt | 1 + .../all/protocol/persistence/MongoProtocolRepositoryTest.kt | 1 + .../question/controller/ExtractionQuestionControllerTest.kt | 1 + .../question/controller/RiskOfBiasQuestionControllerTest.kt | 1 + .../all/question/persistence/MongoQuestionRepositoryTest.kt | 2 ++ .../kotlin/br/all/report/controller/ReportControllerTest.kt | 1 + .../all/review/controller/SystematicStudyControllerTest.kt | 1 + .../persistence/MongoSystematicStudyRepositoryTest.kt | 1 + .../br/all/search/controller/SearchSessionControllerTest.kt | 2 ++ .../search/persistence/MongoSearchSessionRepositoryTest.kt | 2 ++ web/src/test/kotlin/br/all/shared/TestHelperService.kt | 2 ++ .../br/all/study/controller/StudyReviewControllerTest.kt | 2 ++ .../all/study/persistence/MongoStudyReviewRepositoryTest.kt | 3 +++ 38 files changed, 75 insertions(+), 5 deletions(-) diff --git a/account/src/test/kotlin/br/all/domain/user/UserAccountTest.kt b/account/src/test/kotlin/br/all/domain/user/UserAccountTest.kt index fdb27d3ee..25a1e4b8e 100644 --- a/account/src/test/kotlin/br/all/domain/user/UserAccountTest.kt +++ b/account/src/test/kotlin/br/all/domain/user/UserAccountTest.kt @@ -2,11 +2,13 @@ package br.all.domain.user import io.github.serpro69.kfaker.Faker import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Tag import java.time.LocalDateTime import java.util.UUID import kotlin.test.Test import kotlin.test.assertFailsWith +@Tag("UnitTest") class UserAccountTest{ private val faker = Faker() diff --git a/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt index cc4a200c3..42a8eec8a 100644 --- a/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt @@ -1,8 +1,7 @@ +package br.all.application.search.create import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository -import br.all.application.search.create.CreateSearchSessionServiceImpl -import br.all.application.search.create.CreateSearchSessionPresenter import br.all.application.search.util.TestDataFactory import br.all.application.search.repository.SearchSessionRepository import br.all.application.shared.exceptions.EntityNotFoundException @@ -23,9 +22,12 @@ import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.extension.ExtendWith import kotlin.test.Test +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class CreateSearchSessionServiceImplTest { diff --git a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt index 43fc2453b..3ed9029cf 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt @@ -17,9 +17,12 @@ import io.mockk.verify import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class FindAllSearchSessionsBySourceServiceImplTest { diff --git a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt index 6efa7829d..2ebb67cba 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt @@ -16,9 +16,12 @@ import io.mockk.verify import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class FindAllSearchSessionsServiceImplTest { diff --git a/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt index 19ce02703..fae5ee1dc 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt @@ -17,9 +17,12 @@ import io.mockk.verify import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class FindSearchSessionServiceImplTest { @MockK(relaxUnitFun = true) diff --git a/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt index 43a701154..217307515 100644 --- a/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt @@ -16,9 +16,12 @@ import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class UpdateSearchSessionServiceImplTest { diff --git a/review/src/test/kotlin/br/all/application/shared/presenter/PreconditionCheckerTest.kt b/review/src/test/kotlin/br/all/application/shared/presenter/PreconditionCheckerTest.kt index 9bb78ed4f..c69609d0a 100644 --- a/review/src/test/kotlin/br/all/application/shared/presenter/PreconditionCheckerTest.kt +++ b/review/src/test/kotlin/br/all/application/shared/presenter/PreconditionCheckerTest.kt @@ -11,9 +11,11 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import java.util.* +@Tag("UnitTest") class PreconditionCheckerTest { private lateinit var presenter: GenericPresenter<*> diff --git a/review/src/test/kotlin/br/all/architecture/DomainModuleTest.kt b/review/src/test/kotlin/br/all/architecture/DomainModuleTest.kt index f985969ae..1d41e1d00 100644 --- a/review/src/test/kotlin/br/all/architecture/DomainModuleTest.kt +++ b/review/src/test/kotlin/br/all/architecture/DomainModuleTest.kt @@ -6,8 +6,9 @@ import com.tngtech.archunit.junit.AnalyzeClasses import com.tngtech.archunit.junit.ArchTest import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes +import org.junit.jupiter.api.Tag - +@Tag("ArchitectureTest") @AnalyzeClasses(packages = ["br.all"], importOptions = [ImportOption.DoNotIncludeTests::class]) class DomainModuleTest { diff --git a/review/src/test/kotlin/br/all/domain/model/search/SearchSessionTest.kt b/review/src/test/kotlin/br/all/domain/model/search/SearchSessionTest.kt index edb3eada2..dcb7de383 100644 --- a/review/src/test/kotlin/br/all/domain/model/search/SearchSessionTest.kt +++ b/review/src/test/kotlin/br/all/domain/model/search/SearchSessionTest.kt @@ -3,6 +3,7 @@ package br.all.domain.model.search import br.all.domain.model.protocol.SearchSource import br.all.domain.model.user.ResearcherId import br.all.domain.model.review.SystematicStudyId +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.time.LocalDateTime @@ -10,6 +11,7 @@ import java.util.* import kotlin.test.assertEquals +@Tag("UnitTest") class SearchSessionTest { diff --git a/review/src/test/kotlin/br/all/domain/model/study/DoiTest.kt b/review/src/test/kotlin/br/all/domain/model/study/DoiTest.kt index d0845449c..6655ecc1c 100644 --- a/review/src/test/kotlin/br/all/domain/model/study/DoiTest.kt +++ b/review/src/test/kotlin/br/all/domain/model/study/DoiTest.kt @@ -1,8 +1,10 @@ package br.all.domain.model.study import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Tag import kotlin.test.Test +@Tag("UnitTest") class DoiTest { @Test diff --git a/review/src/test/kotlin/br/all/domain/model/study/StudyReviewTest.kt b/review/src/test/kotlin/br/all/domain/model/study/StudyReviewTest.kt index 1a6b27d17..1cfacf2e8 100644 --- a/review/src/test/kotlin/br/all/domain/model/study/StudyReviewTest.kt +++ b/review/src/test/kotlin/br/all/domain/model/study/StudyReviewTest.kt @@ -7,10 +7,12 @@ import br.all.domain.model.search.SearchSessionID import br.all.domain.shared.utils.paragraph import br.all.domain.shared.utils.year import io.github.serpro69.kfaker.Faker +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.assertAll import java.util.* import kotlin.test.* +@Tag("UnitTest") class StudyReviewTest { private val faker = Faker() diff --git a/review/src/test/kotlin/br/all/domain/services/BibtexConverterServiceTest.kt b/review/src/test/kotlin/br/all/domain/services/BibtexConverterServiceTest.kt index 7cce5feba..7b226fa5d 100644 --- a/review/src/test/kotlin/br/all/domain/services/BibtexConverterServiceTest.kt +++ b/review/src/test/kotlin/br/all/domain/services/BibtexConverterServiceTest.kt @@ -8,6 +8,8 @@ import java.util.* import kotlin.test.assertEquals import kotlin.test.assertTrue +@Tag("UnitTest") +@Tag("ServiceTest") class BibtexConverterServiceTest { private lateinit var sut: BibtexConverterService diff --git a/review/src/test/kotlin/br/all/domain/services/ConverterFactoryServiceTest.kt b/review/src/test/kotlin/br/all/domain/services/ConverterFactoryServiceTest.kt index 3964710f2..0242ecd11 100644 --- a/review/src/test/kotlin/br/all/domain/services/ConverterFactoryServiceTest.kt +++ b/review/src/test/kotlin/br/all/domain/services/ConverterFactoryServiceTest.kt @@ -5,10 +5,13 @@ import br.all.domain.model.search.SearchSessionID import br.all.domain.services.RisTestData.testInput as risInput import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import java.util.* import kotlin.test.assertEquals +@Tag("IntegrationTest") +@Tag("ServiceTest") class ConverterFactoryServiceTest { private lateinit var sut: ConverterFactoryService private lateinit var bibtexConverterService: BibtexConverterService diff --git a/review/src/test/kotlin/br/all/domain/services/ReviewSimilarityServiceTest.kt b/review/src/test/kotlin/br/all/domain/services/ReviewSimilarityServiceTest.kt index d008b73ab..72993f0fd 100644 --- a/review/src/test/kotlin/br/all/domain/services/ReviewSimilarityServiceTest.kt +++ b/review/src/test/kotlin/br/all/domain/services/ReviewSimilarityServiceTest.kt @@ -16,6 +16,7 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue @Tag("IntegrationTest") +@Tag("ServiceTest") class ReviewSimilarityServiceTest { private lateinit var sut: ReviewSimilarityService diff --git a/review/src/test/kotlin/br/all/domain/services/RisConverterServiceTest.kt b/review/src/test/kotlin/br/all/domain/services/RisConverterServiceTest.kt index e3ecaa20d..dc1eda98d 100644 --- a/review/src/test/kotlin/br/all/domain/services/RisConverterServiceTest.kt +++ b/review/src/test/kotlin/br/all/domain/services/RisConverterServiceTest.kt @@ -9,6 +9,8 @@ import java.util.* import kotlin.test.assertEquals import kotlin.test.assertTrue +@Tag("UnitTest") +@Tag("ServiceTest") class RisConverterServiceTest { private lateinit var sut: RisConverterService private lateinit var idGeneratorService: IdGeneratorService diff --git a/review/src/test/kotlin/br/all/domain/services/ScoreCalculatorServiceTest.kt b/review/src/test/kotlin/br/all/domain/services/ScoreCalculatorServiceTest.kt index ef35805fa..228c2f31d 100644 --- a/review/src/test/kotlin/br/all/domain/services/ScoreCalculatorServiceTest.kt +++ b/review/src/test/kotlin/br/all/domain/services/ScoreCalculatorServiceTest.kt @@ -11,6 +11,7 @@ import java.util.* import kotlin.test.assertEquals @Tag("IntegrationTest") +@Tag("ServiceTest") class ScoreCalculatorServiceTest { private lateinit var sut: ScoreCalculatorService diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt index 05f63ee8b..1f3348c04 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt @@ -1,6 +1,7 @@ package br.all.domain.shared.ddd import br.all.domain.shared.valueobject.Email +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows @@ -8,6 +9,7 @@ import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue +@Tag("UnitTest") class EmailTest { @Test diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/EntityTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/EntityTest.kt index cc3e586c9..bbf2ae3b7 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/EntityTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/EntityTest.kt @@ -1,8 +1,11 @@ package br.all.domain.shared.ddd import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Tags import org.junit.jupiter.api.Test +@Tag("UnitTest") class EntityTest{ @JvmInline diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/LanguageTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/LanguageTest.kt index aa1ae7d8b..cb82af57a 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/LanguageTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/LanguageTest.kt @@ -1,11 +1,13 @@ package br.all.domain.shared.ddd import br.all.domain.shared.valueobject.Language +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertNotEquals +@Tag("UnitTest") class LanguageTest { @Test diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/NotificationTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/NotificationTest.kt index 404ac1d06..37ed02b9b 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/NotificationTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/NotificationTest.kt @@ -1,8 +1,10 @@ package br.all.domain.shared.ddd import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test +@Tag("UnitTest") class NotificationTest { @Test fun `Should notification with no errors present no error message`(){ diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt index c216b0c64..facc535a6 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/ProtocolIdTest.kt @@ -3,10 +3,12 @@ package br.all.domain.shared.ddd import br.all.domain.model.protocol.ProtocolId import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertNotEquals +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import java.util.* +@Tag("UnitTest") class ProtocolIdTest{ @Test fun `valid ProtocolId`() { diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/TextTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/TextTest.kt index e77cfb994..29df084e3 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/TextTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/TextTest.kt @@ -5,6 +5,7 @@ import org.junit.jupiter.api.* import kotlin.test.assertEquals import kotlin.test.assertNotEquals +@Tag("UnitTest") class TextTest { @Test diff --git a/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt b/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt index 32234cf89..ec2a9d83c 100644 --- a/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/utils/DOITest.kt @@ -2,6 +2,7 @@ package br.all.domain.shared.utils import br.all.domain.shared.valueobject.DOI +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows @@ -9,6 +10,7 @@ import kotlin.test.assertEquals import kotlin.test.assertNotEquals import kotlin.test.assertTrue +@Tag("UnitTest") class DOITest { @Test fun `valid DOI should not throw an exception`() { diff --git a/review/src/test/kotlin/br/all/domain/shared/utils/PhraseTest.kt b/review/src/test/kotlin/br/all/domain/shared/utils/PhraseTest.kt index 8e242cacd..6b3878563 100644 --- a/review/src/test/kotlin/br/all/domain/shared/utils/PhraseTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/utils/PhraseTest.kt @@ -1,10 +1,12 @@ package br.all.domain.shared.utils +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows import kotlin.test.assertEquals +@Tag("UnitTest") class PhraseTest { @Test fun `Should accept words with only lowercase letters`() { diff --git a/review/src/test/kotlin/br/all/infrastructure/ProtocolRepositoryImplTest.kt b/review/src/test/kotlin/br/all/infrastructure/ProtocolRepositoryImplTest.kt index 5c1269c24..b281a2cc8 100644 --- a/review/src/test/kotlin/br/all/infrastructure/ProtocolRepositoryImplTest.kt +++ b/review/src/test/kotlin/br/all/infrastructure/ProtocolRepositoryImplTest.kt @@ -18,8 +18,8 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import java.util.* -@Tag("UnitTests") -@Tag("ServiceTests") +@Tag("UnitTest") +@Tag("ServiceTest") @ExtendWith(MockKExtension::class) class ProtocolRepositoryImplTest { @MockK diff --git a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt index 79d9a3e01..e305b0a7e 100644 --- a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt +++ b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt @@ -24,6 +24,7 @@ import br.all.review.shared.TestDataFactory as SystematicStudyTestDataFactory @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") +@Tag("ControllerTest") @DisplayName("Protocol Controller Integration Tests") class ProtocolControllerTest( @Autowired private val protocolRepository: MongoProtocolRepository, diff --git a/web/src/test/kotlin/br/all/protocol/persistence/MongoProtocolRepositoryTest.kt b/web/src/test/kotlin/br/all/protocol/persistence/MongoProtocolRepositoryTest.kt index fee36a63e..1c8f03b11 100644 --- a/web/src/test/kotlin/br/all/protocol/persistence/MongoProtocolRepositoryTest.kt +++ b/web/src/test/kotlin/br/all/protocol/persistence/MongoProtocolRepositoryTest.kt @@ -10,6 +10,7 @@ import org.springframework.boot.test.context.SpringBootTest @SpringBootTest @Tag("IntegrationTest") +@Tag("RepositoryTest") class MongoProtocolRepositoryTest( @Autowired private val sut: MongoProtocolRepository, ) { diff --git a/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt b/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt index 87fb4da8a..f9b441db8 100644 --- a/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt +++ b/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt @@ -22,6 +22,7 @@ import java.util.* @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") +@Tag("ControllerTest") class ExtractionQuestionControllerTest( @Autowired val repository: MongoQuestionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, diff --git a/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt b/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt index 71f5f4ff0..2ea33c5e5 100644 --- a/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt +++ b/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt @@ -22,6 +22,7 @@ import java.util.* @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") +@Tag("ControllerTest") class RiskOfBiasQuestionControllerTest( @Autowired val repository: MongoQuestionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, diff --git a/web/src/test/kotlin/br/all/question/persistence/MongoQuestionRepositoryTest.kt b/web/src/test/kotlin/br/all/question/persistence/MongoQuestionRepositoryTest.kt index 53c818e05..78c7ddb5c 100644 --- a/web/src/test/kotlin/br/all/question/persistence/MongoQuestionRepositoryTest.kt +++ b/web/src/test/kotlin/br/all/question/persistence/MongoQuestionRepositoryTest.kt @@ -13,6 +13,8 @@ import org.springframework.boot.test.context.SpringBootTest import java.util.UUID @SpringBootTest +@Tag("IntegrationTest") +@Tag("RepositoryTest") class MongoQuestionRepositoryTest( @Autowired private val sut: MongoQuestionRepository, ) { diff --git a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt index 382b3dbed..295b76c0d 100644 --- a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt +++ b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt @@ -31,6 +31,7 @@ import br.all.protocol.shared.TestDataFactory as ProtocolTestDataFactory @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") +@Tag("ControllerTest") @DisplayName("Report Controller Integration Tests") class ReportControllerTest( @Autowired private val studyReviewRepository: MongoStudyReviewRepository, diff --git a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt index facd73d72..43224dc85 100644 --- a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt +++ b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt @@ -23,6 +23,7 @@ import java.util.* @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") +@Tag("ControllerTest") class SystematicStudyControllerTest( @Autowired private val repository: MongoSystematicStudyRepository, @Autowired private val testHelperService: TestHelperService, diff --git a/web/src/test/kotlin/br/all/review/persistence/MongoSystematicStudyRepositoryTest.kt b/web/src/test/kotlin/br/all/review/persistence/MongoSystematicStudyRepositoryTest.kt index 1a81d5f4a..c8c8cf4a6 100644 --- a/web/src/test/kotlin/br/all/review/persistence/MongoSystematicStudyRepositoryTest.kt +++ b/web/src/test/kotlin/br/all/review/persistence/MongoSystematicStudyRepositoryTest.kt @@ -11,6 +11,7 @@ import java.util.* @SpringBootTest @Tag("IntegrationTest") +@Tag("RepositoryTest") class MongoSystematicStudyRepositoryTest( @Autowired private val sut: MongoSystematicStudyRepository, ) { diff --git a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt index 2aef8a289..1d3fe1a22 100644 --- a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt +++ b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt @@ -29,6 +29,8 @@ import java.util.* @SpringBootTest @AutoConfigureMockMvc +@Tag("IntegrationTest") +@Tag("ControllerTest") class SearchSessionControllerTest( @Autowired val repository: MongoSearchSessionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, diff --git a/web/src/test/kotlin/br/all/search/persistence/MongoSearchSessionRepositoryTest.kt b/web/src/test/kotlin/br/all/search/persistence/MongoSearchSessionRepositoryTest.kt index fbeba7400..2f62a0fe3 100644 --- a/web/src/test/kotlin/br/all/search/persistence/MongoSearchSessionRepositoryTest.kt +++ b/web/src/test/kotlin/br/all/search/persistence/MongoSearchSessionRepositoryTest.kt @@ -8,6 +8,8 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import java.util.* @SpringBootTest +@Tag("IntegrationTest") +@Tag("RepositoryTest") class MongoSearchSessionRepositoryTest( @Autowired private val sut: MongoSearchSessionRepository, ) { diff --git a/web/src/test/kotlin/br/all/shared/TestHelperService.kt b/web/src/test/kotlin/br/all/shared/TestHelperService.kt index fd86578cb..bf6d40fac 100644 --- a/web/src/test/kotlin/br/all/shared/TestHelperService.kt +++ b/web/src/test/kotlin/br/all/shared/TestHelperService.kt @@ -4,6 +4,7 @@ import br.all.application.user.repository.UserAccountDto import br.all.application.user.repository.UserAccountRepository import br.all.security.service.ApplicationUser import io.github.serpro69.kfaker.Faker +import org.junit.jupiter.api.Tag import org.springframework.http.MediaType import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors import org.springframework.stereotype.Service @@ -14,6 +15,7 @@ import java.time.LocalDateTime import java.util.* @Service +@Tag("UnitTest") class TestHelperService( private val repository: UserAccountRepository, ) { diff --git a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt index aab3d409f..4735a7e39 100644 --- a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt +++ b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt @@ -27,6 +27,8 @@ import br.all.review.shared.TestDataFactory as SystematicStudyTestDataFactory @SpringBootTest @AutoConfigureMockMvc +@Tag("IntegrationTest") +@Tag("ControllerTest") class StudyReviewControllerTest( @Autowired val repository: MongoStudyReviewRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, diff --git a/web/src/test/kotlin/br/all/study/persistence/MongoStudyReviewRepositoryTest.kt b/web/src/test/kotlin/br/all/study/persistence/MongoStudyReviewRepositoryTest.kt index 1278542e3..1ebed0a45 100644 --- a/web/src/test/kotlin/br/all/study/persistence/MongoStudyReviewRepositoryTest.kt +++ b/web/src/test/kotlin/br/all/study/persistence/MongoStudyReviewRepositoryTest.kt @@ -8,12 +8,15 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import java.util.UUID @SpringBootTest +@Tag("IntegrationTest") +@Tag("RepositoryTest") class MongoStudyReviewRepositoryTest ( @Autowired private val sut: MongoStudyReviewRepository, @Autowired private val idService: StudyReviewIdGeneratorService From 06800f1015cb18931bf0c880ee81ad8a30fcd910 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 18:07:08 -0300 Subject: [PATCH 040/153] build: update spring-boot-starter-parent version --- pom.xml | 2 +- review/pom.xml | 1 - web/pom.xml | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 4585c5d8a..da369b719 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.2 + 3.4.4 diff --git a/review/pom.xml b/review/pom.xml index 6c9336ec0..5d782b870 100644 --- a/review/pom.xml +++ b/review/pom.xml @@ -21,7 +21,6 @@ org.springframework.boot spring-boot-starter-data-mongodb - 3.1.2 org.springframework diff --git a/web/pom.xml b/web/pom.xml index f8203f80e..588d0e033 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -6,7 +6,7 @@ org.springframework.boot spring-boot-starter-parent - 3.1.2 + 3.4.4 From 48737449e2a70ea12f8ab55ca3a6b7da3f0e6bdc Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 18:59:00 -0300 Subject: [PATCH 041/153] chore: add config to ignore tex files --- .gitattributes | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 03085867b..5cbdc074c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ -*.bib linguist-generated +*.tex linguist-detectable=false +*.bib linguist-detectable=false +*.bibtex linguist-detectable=false From bc7e6c38cca24acf0b0d4252e9d9857f279ccaeb Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:14:46 -0300 Subject: [PATCH 042/153] feat: add find criteria by study endpoint --- .../all/report/controller/ReportController.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/web/src/main/kotlin/br/all/report/controller/ReportController.kt b/web/src/main/kotlin/br/all/report/controller/ReportController.kt index 7168c0f06..be2394a3a 100644 --- a/web/src/main/kotlin/br/all/report/controller/ReportController.kt +++ b/web/src/main/kotlin/br/all/report/controller/ReportController.kt @@ -3,6 +3,7 @@ package br.all.report.controller import br.all.application.report.find.service.* import br.all.report.presenter.* import br.all.security.service.AuthenticationInfoService +import br.all.report.presenter.RestfulFindStudyReviewCriteriaPresenter import br.all.utils.LinksFactory import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.media.Content @@ -27,6 +28,7 @@ class ReportController( private val authorNetworkService: AuthorNetworkService, private val findKeywordsService: FindKeywordsService, private val findStudiesByStageService: FindStudiesByStageService, + private val findStudyReviewCriteriaService: FindStudyReviewCriteriaService, private val exportProtocolService: ExportProtocolService, private val findAnswerService: FindAnswerServiceImpl, private val studiesFunnelService: StudiesFunnelService, @@ -350,4 +352,32 @@ class ReportController( findAnswerService.find(presenter, request) return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) } + + @GetMapping("/study-review/{studyReview}/criteria") + @Operation(summary = "Return inclusion and exclusion criteria of study review") + @ApiResponses( + value = [ + ApiResponse( + responseCode = "200", description = "Success getting criteria of a review", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = FindStudyReviewCriteriaService.ResponseModel::class) + )] + ), + ApiResponse(responseCode = "401", description = "Fail getting criteria of a review - unauthenticated user", + content = [Content(schema = Schema(hidden = true))]), + ApiResponse(responseCode = "403", description = "Fail getting criteria of a review - unauthorized user", + content = [Content(schema = Schema(hidden = true))]), + ] + ) + fun findCriteria( + @PathVariable systematicStudyId: UUID, + @PathVariable studyReview: Long + ): ResponseEntity<*> { + val presenter = RestfulFindStudyReviewCriteriaPresenter(linksFactory) + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = FindStudyReviewCriteriaService.RequestModel(userId, systematicStudyId, studyReview) + findStudyReviewCriteriaService.findCriteria(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } } \ No newline at end of file From b868df20856f6c10e7c64e5e4711061888afebd4 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:15:17 -0300 Subject: [PATCH 043/153] feat: find criteria by study endpoint presenter --- .../find/presenter/FindStudyReviewCriteriaPresenter.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/report/find/presenter/FindStudyReviewCriteriaPresenter.kt diff --git a/review/src/main/kotlin/br/all/application/report/find/presenter/FindStudyReviewCriteriaPresenter.kt b/review/src/main/kotlin/br/all/application/report/find/presenter/FindStudyReviewCriteriaPresenter.kt new file mode 100644 index 000000000..90e2ad4cf --- /dev/null +++ b/review/src/main/kotlin/br/all/application/report/find/presenter/FindStudyReviewCriteriaPresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.report.find.presenter + +import br.all.application.shared.presenter.GenericPresenter +import br.all.application.report.find.service.FindStudyReviewCriteriaService + +interface FindStudyReviewCriteriaPresenter: GenericPresenter \ No newline at end of file From 46e0f28aa5aa99ebb8d84d3fcd9f20cd1f17db67 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:15:25 -0300 Subject: [PATCH 044/153] feat: find criteria by study endpoint service --- .../service/FindStudyReviewCriteriaService.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaService.kt diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaService.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaService.kt new file mode 100644 index 000000000..e97df28f4 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaService.kt @@ -0,0 +1,22 @@ +package br.all.application.report.find.service + +import br.all.application.report.find.presenter.FindStudyReviewCriteriaPresenter +import java.util.* + +interface FindStudyReviewCriteriaService { + fun findCriteria(presenter: FindStudyReviewCriteriaPresenter, request: RequestModel) + + data class RequestModel( + val userId: UUID, + val systematicStudyId: UUID, + val studyReviewId: Long + ) + + data class ResponseModel( + val userId: UUID, + val systematicStudyId: UUID, + val studyReviewId: Long, + val inclusionCriteria: Set, + val exclusionCriteria: Set + ) +} \ No newline at end of file From 73b7a68f47540fe0df5fa6919c6044a66cdfd9b5 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:15:29 -0300 Subject: [PATCH 045/153] feat: find criteria by study endpoint impl --- .../FindStudyReviewCriteriaServiceImpl.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt new file mode 100644 index 000000000..f1b8bc5ac --- /dev/null +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt @@ -0,0 +1,60 @@ +package br.all.application.report.find.service + +import br.all.application.protocol.repository.CriterionDto +import br.all.application.protocol.repository.ProtocolRepository +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.report.find.presenter.FindStudyReviewCriteriaPresenter +import br.all.application.study.repository.StudyReviewDto +import br.all.application.study.repository.StudyReviewRepository +import br.all.application.user.CredentialsService +import br.all.domain.model.review.SystematicStudy + +class FindStudyReviewCriteriaServiceImpl( + private val systematicStudyRepository: SystematicStudyRepository, + private val studyReviewRepository: StudyReviewRepository, + private val credentialsService: CredentialsService, + private val protocolRepository: ProtocolRepository, +): FindStudyReviewCriteriaService { + override fun findCriteria( + presenter: FindStudyReviewCriteriaPresenter, + request: FindStudyReviewCriteriaService.RequestModel + ) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + + if(presenter.isDone()) return + + val criteriaSet = protocolRepository.findById(request.systematicStudyId)?.eligibilityCriteria?: emptyList() + + val studyReview = studyReviewRepository.findById(request.systematicStudyId, request.studyReviewId)!! + + val inclusionCriteria = getCriteriaByType(criteriaSet, studyReview, "INCLUSION") + val exclusionCriteria = getCriteriaByType(criteriaSet, studyReview, "EXCLUSION") + + val response = FindStudyReviewCriteriaService.ResponseModel( + userId = request.userId, + systematicStudyId = request.systematicStudyId, + studyReviewId = request.studyReviewId, + inclusionCriteria = inclusionCriteria, + exclusionCriteria = exclusionCriteria, + ) + + presenter.prepareSuccessView(response) + } + + private fun getCriteriaByType( + criteriaSet: Collection, + studyReview: StudyReviewDto, + type: String + ): Set { + return criteriaSet + .filter { it.type == type && it.description in studyReview.criteria } + .map { it.description }.toSet() + } +} \ No newline at end of file From c9c5835ed846fb2ac7094c2577d42aa8ef381615 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:15:36 -0300 Subject: [PATCH 046/153] feat: find criteria by study endpoint link factory --- web/src/main/kotlin/br/all/utils/LinksFactory.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/src/main/kotlin/br/all/utils/LinksFactory.kt b/web/src/main/kotlin/br/all/utils/LinksFactory.kt index ce4765c8b..dcea9b1fe 100644 --- a/web/src/main/kotlin/br/all/utils/LinksFactory.kt +++ b/web/src/main/kotlin/br/all/utils/LinksFactory.kt @@ -316,5 +316,12 @@ class LinksFactory { questionId ) }.withRel("find-answer").withType("GET") -} + fun findStudyReviewCriteria(systematicStudyId: UUID, studyReviewId: Long): Link = + linkTo { + findCriteria( + systematicStudyId, + studyReviewId + ) + }.withRel("find-study-criteria").withType("GET") +} From 787d7e89826184b392751ec2c0533b8a7723b520 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:15:42 -0300 Subject: [PATCH 047/153] feat: find criteria by study endpoint bean --- .../controller/ReportControllerConfiguration.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt b/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt index 5712b44cf..2edc0fc1c 100644 --- a/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt +++ b/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt @@ -137,4 +137,17 @@ class ReportControllerConfiguration { systematicStudyRepository, questionRepository ) + + @Bean + fun findStudyReviewCriteriaService( + systematicStudyRepository: SystematicStudyRepository, + studyReviewRepository: StudyReviewRepository, + credentialsService: CredentialsService, + protocolRepository: ProtocolRepository, + ) = FindStudyReviewCriteriaServiceImpl( + systematicStudyRepository, + studyReviewRepository, + credentialsService, + protocolRepository + ) } \ No newline at end of file From b0c7be440a857d1f88c7710f0fda20e05db523f1 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:16:02 -0300 Subject: [PATCH 048/153] test: find criteria by study endpoint happy path test --- .../report/controller/ReportControllerTest.kt | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt index 295b76c0d..bd3d94aac 100644 --- a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt +++ b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt @@ -27,7 +27,6 @@ import br.all.review.shared.TestDataFactory as SystematicStudyTestDataFactory import br.all.study.utils.TestDataFactory as StudyReviewTestDataFactory import br.all.protocol.shared.TestDataFactory as ProtocolTestDataFactory - @SpringBootTest @AutoConfigureMockMvc @Tag("IntegrationTest") @@ -119,6 +118,9 @@ class ReportControllerTest( private fun studiesFunnelUrl() = "$baseReportUrl/studies-funnel" + private fun findStudyReviewCriteria(studyReviewId: Long) = + "$baseReportUrl/study-review/$studyReviewId/criteria" + private fun findKeywordsUrl(filter: String?) = if (filter.isNullOrBlank()) "$baseReportUrl/keywords" @@ -695,4 +697,37 @@ class ReportControllerTest( } } } + + @Nested + @DisplayName("When finding criteria of a study review") + inner class WhenFindingCriteriaOfAStudyReview { + @Test + fun `should return 200 and find correctly the criteria`() { + val systematicStudyId = systematicStudy.id + val studyReviewId = 1_000L + + val studyReview = studyReviewDataFactory.reviewDocument( + criteria = setOf("criteria 1", "criteria 2"), + systematicStudyId = systematicStudyId, + studyReviewId = studyReviewId, + ) + studyReviewRepository.save(studyReview) + + val criteria1 = protocolDataFactory.createCriteria("INCLUSION", "criteria 1") + + val criteria2 = protocolDataFactory.createCriteria("EXCLUSION", "criteria 2") + + val protocol = protocolDataFactory.createProtocolDocument( + id = systematicStudyId, + selectionCriteria = setOf(criteria1, criteria2) + ) + protocolRepository.save(protocol) + + mockMvc.perform( + get(findStudyReviewCriteria(studyReviewId = studyReviewId)) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + ) + .andExpect(status().isOk) + } + } } From bfdfd07f975e13737a2b0d110085cd496bf4a1f3 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:16:22 -0300 Subject: [PATCH 049/153] test: create function to generate criteria --- .../test/kotlin/br/all/protocol/shared/TestDataFactory.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/web/src/test/kotlin/br/all/protocol/shared/TestDataFactory.kt b/web/src/test/kotlin/br/all/protocol/shared/TestDataFactory.kt index a0da57f75..0a47a7b1e 100644 --- a/web/src/test/kotlin/br/all/protocol/shared/TestDataFactory.kt +++ b/web/src/test/kotlin/br/all/protocol/shared/TestDataFactory.kt @@ -62,6 +62,14 @@ class TestDataFactory { picoc, ) + fun createCriteria( + type: String, + description: String, + ) = CriterionDto( + type = type, + description = description, + ) + private fun eligibilityCriteria() = List(5) { CriterionDto(faker.paragraph(5), faker.random.randomValue(listOf("INCLUSION", "EXCLUSION"))) }.toSet() From e6dabd92bc7c55c8562d5cb8af332afcfef29368 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:16:39 -0300 Subject: [PATCH 050/153] test: remove unused imports and make variable private --- web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt b/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt index 0f7fe576d..bf5ded6e2 100644 --- a/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt +++ b/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt @@ -1,14 +1,12 @@ package br.all.review.shared -import br.all.application.user.repository.UserAccountDto import br.all.infrastructure.review.SystematicStudyDocument import io.github.serpro69.kfaker.Faker -import java.time.LocalDateTime import java.util.* class TestDataFactory { private val faker = Faker() - val researcherId: UUID = UUID.randomUUID() + private val researcherId: UUID = UUID.randomUUID() val systematicStudyId: UUID = UUID.randomUUID() val ownerId: UUID = UUID.randomUUID() From 907410996c10f53527735d4a77ba8dbcdfffd628 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:19:07 -0300 Subject: [PATCH 051/153] feat: restful implementation of presenter --- ...RestfulFindStudyReviewCriteriaPresenter.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 web/src/main/kotlin/br/all/report/presenter/RestfulFindStudyReviewCriteriaPresenter.kt diff --git a/web/src/main/kotlin/br/all/report/presenter/RestfulFindStudyReviewCriteriaPresenter.kt b/web/src/main/kotlin/br/all/report/presenter/RestfulFindStudyReviewCriteriaPresenter.kt new file mode 100644 index 000000000..017ed9d37 --- /dev/null +++ b/web/src/main/kotlin/br/all/report/presenter/RestfulFindStudyReviewCriteriaPresenter.kt @@ -0,0 +1,37 @@ +package br.all.report.presenter + +import br.all.application.report.find.presenter.FindStudyReviewCriteriaPresenter +import br.all.application.report.find.service.FindStudyReviewCriteriaService +import br.all.shared.error.createErrorResponseFrom +import br.all.utils.LinksFactory +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.http.ResponseEntity.status + +class RestfulFindStudyReviewCriteriaPresenter( + private val linksFactory: LinksFactory +): FindStudyReviewCriteriaPresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: FindStudyReviewCriteriaService.ResponseModel) { + val restfulResponse = ViewModel( + response.exclusionCriteria, + response.inclusionCriteria + ) + + val selfRef = linksFactory.findStudyReviewCriteria(response.systematicStudyId, response.studyReviewId) + + restfulResponse.add(selfRef) + responseEntity = status(HttpStatus.OK).body(restfulResponse) + } + + override fun prepareFailView(throwable: Throwable)= run { responseEntity = createErrorResponseFrom(throwable) } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val exclusionCriteria: Set, + val inclusionCriteria: Set, + ) : RepresentationModel() +} \ No newline at end of file From da75ba22a0885fb038740f0e40012583c4291c22 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 13 Jun 2025 23:21:33 -0300 Subject: [PATCH 052/153] refactor: studyReviewId value --- .../br/all/report/controller/ReportControllerTest.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt index bd3d94aac..8c3cb88c4 100644 --- a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt +++ b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt @@ -704,7 +704,12 @@ class ReportControllerTest( @Test fun `should return 200 and find correctly the criteria`() { val systematicStudyId = systematicStudy.id - val studyReviewId = 1_000L + // o intelli j tava reclamando que o valor do id era sempre o mesmo + // então é por isso que tem esse negócio ai, qualquer coisa só + // coloca val studyReviewId = 1000L + val seed = System.currentTimeMillis() + val studyReviewId = (seed * 31) % Long.MAX_VALUE + val studyReview = studyReviewDataFactory.reviewDocument( criteria = setOf("criteria 1", "criteria 2"), From b476ebd9804c4b319dcd864c8b268fd3de8d9a47 Mon Sep 17 00:00:00 2001 From: lucas-ifsp Date: Sun, 15 Jun 2025 16:00:13 -0300 Subject: [PATCH 053/153] fix: solve merge conflict with scas module --- .idea/encodings.xml | 1 + pom.xml | 1 + .../create/CreateSearchSessionServiceImpl.kt | 6 ++ .../SelectionStatusSuggestionService.kt | 23 +++++ scas/pom.xml | 94 +++++++++++++++++++ .../kotlin/br/ifsp/octaviano/Principal.kt | 17 ++++ .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 11 +++ 7 files changed, 153 insertions(+) create mode 100644 review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt create mode 100644 scas/pom.xml create mode 100644 scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt create mode 100644 scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 05b89fd73..44efd8de8 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -7,6 +7,7 @@ + diff --git a/pom.xml b/pom.xml index 0fba64dbb..e0f2e0a6b 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ review web account + scas diff --git a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt index 200bd815d..2fe2d3e2a 100644 --- a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt @@ -73,6 +73,12 @@ class CreateSearchSessionServiceImpl( mutableSetOf(source) ) + /* + criar os request StudyInfo a partir dos studyReviews (infos) + val selectionSuggestions = selectionSuggestion.buildSuggestions(infos) + studyReviews.foreach(it.setSuggestedStatus(selectionsuggstion.filter(it.getId) + */ + val scoredStudyReviews = scoreCalculatorService.applyScoreToManyStudyReviews(studyReviews, protocolDto.keywords) studyReviewRepository.saveOrUpdateBatch(scoredStudyReviews.map { it.toDto() }) diff --git a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt new file mode 100644 index 000000000..8f77e08c2 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt @@ -0,0 +1,23 @@ +package br.all.domain.services + +import br.all.domain.model.study.StudyReview + +interface SelectionStatusSuggestionService { + fun buildSuggestions(request: RequestModel) : ResponseModel + + data class RequestModel(val studiesInfo: List) + + data class ResponseModel(val studySuggestions: List) + + data class StudyReviewInfo( + val studyReviewId: Long, + val studyReviewScore: Int, + val studyReviewCitations: Int, + val studyReviewYear: Int + ) + + data class StudyStatusSuggestion( + val studyReviewId: Long, + val studyReviewScore: String, + ) +} \ No newline at end of file diff --git a/scas/pom.xml b/scas/pom.xml new file mode 100644 index 000000000..14a1e5fb8 --- /dev/null +++ b/scas/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + br.all + systematic + 1.0-SNAPSHOT + + + scas + + + UTF-8 + official + 1.8 + + + + + mavenCentral + https://repo1.maven.org/maven2/ + + + + + src/main/kotlin + src/test/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + maven-surefire-plugin + + + maven-failsafe-plugin + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + MainKt + + + + + + + + org.jetbrains.kotlin + kotlin-test-junit5 + 1.9.23 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.10.0 + test + + + org.jetbrains.kotlin + kotlin-stdlib + 1.9.23 + + + br.all + review + 1.0-SNAPSHOT + compile + + + + \ No newline at end of file diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt new file mode 100644 index 000000000..de2a88d45 --- /dev/null +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -0,0 +1,17 @@ +package br.ifsp.octaviano + +import br.all.domain.services.SelectionStatusSuggestionService +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel + +class Principal { + fun main(args: Array) { + val input = listOf( + SelectionStatusSuggestionService.StudyReviewInfo(1, 231, 3, 2023), + ) + + val service: SelectionStatusSuggestionService = ScasImpl() + val responseModel = service.buildSuggestions(RequestModel(input)) + + responseModel.studySuggestions.forEach { println(it) } + } +} \ No newline at end of file diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt new file mode 100644 index 000000000..869d4f444 --- /dev/null +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -0,0 +1,11 @@ +package br.ifsp.octaviano + +import br.all.domain.services.SelectionStatusSuggestionService +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.ResponseModel + +class ScasImpl : SelectionStatusSuggestionService { + override fun buildSuggestions(request: RequestModel): ResponseModel { + TODO("Not yet implemented") + } +} \ No newline at end of file From cf76624c84385991166e47ed17310725ec5b046a Mon Sep 17 00:00:00 2001 From: Shoji Date: Tue, 20 Aug 2024 00:08:11 -0300 Subject: [PATCH 054/153] feat(scas): implement interface with approximate classification values --- .../SelectionStatusSuggestionService.kt | 6 +- .../kotlin/br/ifsp/octaviano/Principal.kt | 23 ++-- .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 110 +++++++++++++++++- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt index 8f77e08c2..3fa220dfd 100644 --- a/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt +++ b/review/src/main/kotlin/br/all/domain/services/SelectionStatusSuggestionService.kt @@ -1,13 +1,11 @@ package br.all.domain.services -import br.all.domain.model.study.StudyReview - interface SelectionStatusSuggestionService { fun buildSuggestions(request: RequestModel) : ResponseModel data class RequestModel(val studiesInfo: List) - data class ResponseModel(val studySuggestions: List) + data class ResponseModel(val studySuggestions: List) data class StudyReviewInfo( val studyReviewId: Long, @@ -20,4 +18,4 @@ interface SelectionStatusSuggestionService { val studyReviewId: Long, val studyReviewScore: String, ) -} \ No newline at end of file +} diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt index de2a88d45..5759f5378 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -1,17 +1,18 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.* -class Principal { - fun main(args: Array) { - val input = listOf( - SelectionStatusSuggestionService.StudyReviewInfo(1, 231, 3, 2023), - ) +fun main() { + val input = listOf( + StudyReviewInfo(1, 21, 10, 2023), + StudyReviewInfo(2, 0, 0, 2006), + StudyReviewInfo(3, 54, 40, 2023), + StudyReviewInfo(4, 34, 30, 2015), + ) - val service: SelectionStatusSuggestionService = ScasImpl() - val responseModel = service.buildSuggestions(RequestModel(input)) + val service: SelectionStatusSuggestionService = ScasImpl() + val responseModel = service.buildSuggestions(RequestModel(input)) - responseModel.studySuggestions.forEach { println(it) } - } -} \ No newline at end of file + responseModel.studySuggestions.forEach { println(it) } +} diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt index 869d4f444..8d6f2e63c 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -1,11 +1,113 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.RequestModel -import br.all.domain.services.SelectionStatusSuggestionService.ResponseModel +import br.all.domain.services.SelectionStatusSuggestionService.* class ScasImpl : SelectionStatusSuggestionService { + private enum class HazyValues { + LOW, MEDIUM, HIGH + } + + private data class StudyInfo( + val studyReviewId: Long, + val studyReviewScore: Int, + val studyReviewCitations: Int, + val studyReviewYear: Int, + var studyReviewNormalizedScore: Double? = null, + var studyScoreClassification: HazyValues? = null, + var studyReviewCitationCoefficient: Double? = null, + var studyReviewNormalizedCitationCoefficient: Double? = null, + var studyCitationCoefficientClassification: HazyValues? = null, + var studyReviewSuggestion: String? = null, + ) + override fun buildSuggestions(request: RequestModel): ResponseModel { - TODO("Not yet implemented") + val studiesInfo = convertToCompleteStudyInfo(request.studiesInfo) + + val mostRecentYear = getMostRecentYear(studiesInfo) + + calculateCitationCoefficients(studiesInfo, mostRecentYear) + normalizeScores(studiesInfo) + normalizeCitationCoefficients(studiesInfo) + classifyNormalizedScores(studiesInfo) + classifyNormalizedCitationCoefficients(studiesInfo) + val studySuggestions = suggestStudiesClassification(studiesInfo) + + return ResponseModel(studySuggestions) + } + + private fun convertToCompleteStudyInfo(studiesInfo: List): List { + return studiesInfo.map { + StudyInfo( + it.studyReviewId, it.studyReviewScore, it.studyReviewCitations, it.studyReviewYear + ) + } + } + + private fun getMostRecentYear(studiesInfo: List): Int { + val years = studiesInfo.map { it.studyReviewYear } + return years.max() + } + + private fun calculateCitationCoefficients( + studiesInfo: List, mostRecentYear: Int, index: Double = 0.05 + ) { + studiesInfo.forEach { + it.studyReviewCitationCoefficient = + (1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear)) + } + } + + private fun normalizeScores(studiesInfo: List) { + val scores = studiesInfo.map { it.studyReviewScore } + val max = scores.max() + studiesInfo.forEach { it.studyReviewNormalizedScore = it.studyReviewScore.toDouble() / max } + } + + private fun normalizeCitationCoefficients(studiesInfo: List) { + val citationCoefficients = studiesInfo.map { it.studyReviewCitationCoefficient!! } + val max = citationCoefficients.max() + studiesInfo.forEach { + it.studyReviewNormalizedCitationCoefficient = it.studyReviewCitationCoefficient?.div(max) + } + } + + private fun classifyNormalizedScores(studiesInfo: List) { + studiesInfo.forEach { + it.studyScoreClassification = when (it.studyReviewNormalizedScore!!) { + in 0.0..0.14 -> HazyValues.LOW + in 0.15..0.45 -> HazyValues.MEDIUM + else -> HazyValues.HIGH + } + } + } + + private fun classifyNormalizedCitationCoefficients(studiesInfo: List) { + studiesInfo.forEach { + it.studyCitationCoefficientClassification = when (it.studyReviewNormalizedCitationCoefficient!!) { + in 0.0..0.1 -> HazyValues.LOW + in 0.11..0.19 -> HazyValues.MEDIUM + else -> HazyValues.HIGH + } + } + } + + private fun suggestStudiesClassification(studiesInfo: List): List { + studiesInfo.forEach { + it.studyReviewSuggestion = when { + it.studyScoreClassification == HazyValues.HIGH + && it.studyCitationCoefficientClassification == HazyValues.HIGH + || it.studyCitationCoefficientClassification == HazyValues.MEDIUM + -> "Automatic inclusion" + + it.studyScoreClassification == HazyValues.LOW + && it.studyCitationCoefficientClassification == HazyValues.MEDIUM + || it.studyCitationCoefficientClassification == HazyValues.LOW + -> "Automatic exclusion" + + else -> "Manual review" + } + } + return studiesInfo.map { StudyStatusSuggestion(it.studyReviewId, it.studyReviewSuggestion!!) } } -} \ No newline at end of file +} From 11222cdebce3bd0750722681459e172a1ffe2d05 Mon Sep 17 00:00:00 2001 From: Shoji Date: Fri, 25 Oct 2024 16:27:57 -0300 Subject: [PATCH 055/153] feat(scas): classify studies with scas m2 values --- .../kotlin/br/ifsp/octaviano/Principal.kt | 104 +++++++++++++++++- .../main/kotlin/br/ifsp/octaviano/ScasImpl.kt | 56 ++++++---- 2 files changed, 134 insertions(+), 26 deletions(-) diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt index 5759f5378..422b9121d 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/Principal.kt @@ -1,14 +1,108 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService -import br.all.domain.services.SelectionStatusSuggestionService.* +import br.all.domain.services.SelectionStatusSuggestionService.RequestModel +import br.all.domain.services.SelectionStatusSuggestionService.StudyReviewInfo fun main() { val input = listOf( - StudyReviewInfo(1, 21, 10, 2023), - StudyReviewInfo(2, 0, 0, 2006), - StudyReviewInfo(3, 54, 40, 2023), - StudyReviewInfo(4, 34, 30, 2015), + StudyReviewInfo(1, 84, 1, 2006), + StudyReviewInfo(2, 83, 0, 2006), + StudyReviewInfo(3, 71, 1, 2006), + StudyReviewInfo(4, 59, 0, 2007), + StudyReviewInfo(5, 56, 0, 2007), + StudyReviewInfo(6, 55, 6, 2004), + StudyReviewInfo(7, 55, 10, 2006), + StudyReviewInfo(8, 55, 9, 2006), + StudyReviewInfo(9, 52, 18, 2003), + StudyReviewInfo(10, 49, 35, 2004), + StudyReviewInfo(11, 48, 2, 2006), + StudyReviewInfo(12, 45, 0, 2005), + StudyReviewInfo(13, 44, 2, 2006), + StudyReviewInfo(14, 43, 3, 2005), + StudyReviewInfo(15, 41, 0, 2006), + StudyReviewInfo(16, 40, 0, 2007), + StudyReviewInfo(17, 39, 0, 2007), + StudyReviewInfo(18, 38, 0, 2006), + StudyReviewInfo(19, 38, 7, 2005), + StudyReviewInfo(20, 38, 7, 2005), + StudyReviewInfo(21, 35, 1, 2007), + StudyReviewInfo(22, 35, 0, 2007), + StudyReviewInfo(23, 35, 0, 2007), + StudyReviewInfo(24, 34, 0, 2007), + StudyReviewInfo(25, 34, 1, 2006), + StudyReviewInfo(26, 34, 0, 2006), + StudyReviewInfo(27, 32, 0, 2007), + StudyReviewInfo(28, 32, 0, 2007), + StudyReviewInfo(29, 32, 2, 2005), + StudyReviewInfo(30, 32, 0, 2007), + StudyReviewInfo(31, 31, 1, 2004), + StudyReviewInfo(32, 31, 0, 2007), + StudyReviewInfo(33, 31, 8, 2002), + StudyReviewInfo(34, 29, 0, 2006), + StudyReviewInfo(35, 29, 0, 2006), + StudyReviewInfo(36, 29, 0, 2007), + StudyReviewInfo(37, 29, 9, 2006), + StudyReviewInfo(38, 28, 0, 2006), + StudyReviewInfo(39, 28, 0, 2007), + StudyReviewInfo(40, 27, 0, 2006), + StudyReviewInfo(41, 27, 0, 2006), + StudyReviewInfo(42, 26, 0, 2005), + StudyReviewInfo(43, 26, 4, 2005), + StudyReviewInfo(44, 25, 0, 2006), + StudyReviewInfo(45, 25, 1, 2006), + StudyReviewInfo(46, 25, 6, 2005), + StudyReviewInfo(47, 24, 0, 2007), + StudyReviewInfo(48, 23, 0, 2006), + StudyReviewInfo(49, 22, 0, 2007), + StudyReviewInfo(50, 22, 0, 2004), + StudyReviewInfo(51, 22, 3, 2006), + StudyReviewInfo(52, 22, 0, 2005), + StudyReviewInfo(53, 22, 0, 2007), + StudyReviewInfo(54, 20, 6, 2006), + StudyReviewInfo(55, 20, 1, 2004), + StudyReviewInfo(56, 20, 0, 2007), + StudyReviewInfo(57, 18, 0, 2007), + StudyReviewInfo(58, 18, 3, 2005), + StudyReviewInfo(59, 17, 0, 2003), + StudyReviewInfo(60, 17, 6, 2005), + StudyReviewInfo(61, 17, 1, 2005), + StudyReviewInfo(62, 17, 0, 2007), + StudyReviewInfo(63, 16, 0, 2006), + StudyReviewInfo(64, 16, 0, 2006), + StudyReviewInfo(65, 16, 0, 2007), + StudyReviewInfo(66, 15, 0, 2004), + StudyReviewInfo(67, 15, 0, 2000), + StudyReviewInfo(68, 15, 0, 2007), + StudyReviewInfo(69, 14, 0, 2007), + StudyReviewInfo(70, 13, 0, 2007), + StudyReviewInfo(71, 13, 5, 2005), + StudyReviewInfo(72, 13, 0, 2006), + StudyReviewInfo(73, 11, 3, 2005), + StudyReviewInfo(74, 11, 0, 2007), + StudyReviewInfo(75, 11, 0, 2007), + StudyReviewInfo(76, 11, 0, 2007), + StudyReviewInfo(77, 11, 0, 2007), + StudyReviewInfo(78, 11, 0, 2007), + StudyReviewInfo(79, 10, 0, 2006), + StudyReviewInfo(80, 10, 0, 2007), + StudyReviewInfo(81, 9, 0, 2000), + StudyReviewInfo(82, 9, 0, 2007), + StudyReviewInfo(83, 9, 0, 2006), + StudyReviewInfo(84, 9, 0, 2007), + StudyReviewInfo(85, 8, 0, 2007), + StudyReviewInfo(86, 8, 0, 2006), + StudyReviewInfo(87, 8, 0, 2006), + StudyReviewInfo(88, 8, 0, 2002), + StudyReviewInfo(89, 8, 0, 2006), + StudyReviewInfo(90, 8, 0, 2007), + StudyReviewInfo(91, 8, 0, 2003), + StudyReviewInfo(92, 6, 0, 2006), + StudyReviewInfo(93, 6, 0, 2007), + StudyReviewInfo(94, 6, 0, 2003), + StudyReviewInfo(95, 3, 0, 2006), + StudyReviewInfo(96, 3, 0, 2007), + StudyReviewInfo(97, 3, 0, 2007), ) val service: SelectionStatusSuggestionService = ScasImpl() diff --git a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt index 8d6f2e63c..9ea4bee23 100644 --- a/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt +++ b/scas/src/main/kotlin/br/ifsp/octaviano/ScasImpl.kt @@ -2,6 +2,7 @@ package br.ifsp.octaviano import br.all.domain.services.SelectionStatusSuggestionService import br.all.domain.services.SelectionStatusSuggestionService.* +import java.math.RoundingMode class ScasImpl : SelectionStatusSuggestionService { private enum class HazyValues { @@ -29,6 +30,7 @@ class ScasImpl : SelectionStatusSuggestionService { calculateCitationCoefficients(studiesInfo, mostRecentYear) normalizeScores(studiesInfo) normalizeCitationCoefficients(studiesInfo) + classifyNormalizedScores(studiesInfo) classifyNormalizedCitationCoefficients(studiesInfo) val studySuggestions = suggestStudiesClassification(studiesInfo) @@ -54,60 +56,72 @@ class ScasImpl : SelectionStatusSuggestionService { ) { studiesInfo.forEach { it.studyReviewCitationCoefficient = - (1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear)) + ((1 + it.studyReviewCitations) * (1 - index * (mostRecentYear - it.studyReviewYear))).toBigDecimal().setScale(2, RoundingMode.HALF_EVEN).toDouble() } } private fun normalizeScores(studiesInfo: List) { val scores = studiesInfo.map { it.studyReviewScore } - val max = scores.max() - studiesInfo.forEach { it.studyReviewNormalizedScore = it.studyReviewScore.toDouble() / max } + val max = scores.max().toDouble() + studiesInfo.forEach { it.studyReviewNormalizedScore = (it.studyReviewScore / max).toBigDecimal().setScale(2, RoundingMode.HALF_EVEN).toDouble() + } } private fun normalizeCitationCoefficients(studiesInfo: List) { - val citationCoefficients = studiesInfo.map { it.studyReviewCitationCoefficient!! } + val citationCoefficients = studiesInfo.mapNotNull { it.studyReviewCitationCoefficient } val max = citationCoefficients.max() studiesInfo.forEach { - it.studyReviewNormalizedCitationCoefficient = it.studyReviewCitationCoefficient?.div(max) + it.studyReviewNormalizedCitationCoefficient = (it.studyReviewCitationCoefficient?.div(max))?.toBigDecimal()?.setScale(2, RoundingMode.HALF_EVEN)?.toDouble() } } private fun classifyNormalizedScores(studiesInfo: List) { studiesInfo.forEach { - it.studyScoreClassification = when (it.studyReviewNormalizedScore!!) { - in 0.0..0.14 -> HazyValues.LOW - in 0.15..0.45 -> HazyValues.MEDIUM - else -> HazyValues.HIGH + it.studyReviewNormalizedScore?.let { studyReviewNormalizedScore -> run { + it.studyScoreClassification = when { + studyReviewNormalizedScore >= 0.46 -> HazyValues.HIGH + studyReviewNormalizedScore >= 0.13 -> HazyValues.MEDIUM + else -> HazyValues.LOW + } } - } + }} } private fun classifyNormalizedCitationCoefficients(studiesInfo: List) { studiesInfo.forEach { - it.studyCitationCoefficientClassification = when (it.studyReviewNormalizedCitationCoefficient!!) { - in 0.0..0.1 -> HazyValues.LOW - in 0.11..0.19 -> HazyValues.MEDIUM - else -> HazyValues.HIGH + it.studyReviewNormalizedCitationCoefficient?.let { studyReviewNormalizedCitationCoefficient -> run { + it.studyCitationCoefficientClassification = when { + studyReviewNormalizedCitationCoefficient >= 0.395 -> HazyValues.HIGH + studyReviewNormalizedCitationCoefficient >= 0.12 -> HazyValues.MEDIUM + else -> HazyValues.LOW + } } - } + }} } private fun suggestStudiesClassification(studiesInfo: List): List { studiesInfo.forEach { it.studyReviewSuggestion = when { - it.studyScoreClassification == HazyValues.HIGH - && it.studyCitationCoefficientClassification == HazyValues.HIGH - || it.studyCitationCoefficientClassification == HazyValues.MEDIUM + (it.studyScoreClassification == HazyValues.HIGH + && (it.studyCitationCoefficientClassification == HazyValues.HIGH + || it.studyCitationCoefficientClassification == HazyValues.MEDIUM) + ) || (it.studyScoreClassification == HazyValues.MEDIUM + && it.studyCitationCoefficientClassification == HazyValues.HIGH) -> "Automatic inclusion" it.studyScoreClassification == HazyValues.LOW - && it.studyCitationCoefficientClassification == HazyValues.MEDIUM - || it.studyCitationCoefficientClassification == HazyValues.LOW + && (it.studyCitationCoefficientClassification == HazyValues.MEDIUM + || it.studyCitationCoefficientClassification == HazyValues.LOW) -> "Automatic exclusion" else -> "Manual review" } } - return studiesInfo.map { StudyStatusSuggestion(it.studyReviewId, it.studyReviewSuggestion!!) } + + return studiesInfo.mapNotNull { it.studyReviewSuggestion?.let { studyReviewSuggestion -> + StudyStatusSuggestion(it.studyReviewId, + studyReviewSuggestion + ) + } } } } From 0c8ae63c8bacc84977cafd2c95ae0dba0ab1e5b4 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Tue, 17 Jun 2025 12:28:36 -0300 Subject: [PATCH 056/153] build: add sonarqube to github actions --- .github/workflows/sonarqube.yml | 36 +++++++++++++++++++++++++++++++++ pom.xml | 2 ++ 2 files changed, 38 insertions(+) create mode 100644 .github/workflows/sonarqube.yml diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml new file mode 100644 index 000000000..d1c691708 --- /dev/null +++ b/.github/workflows/sonarqube.yml @@ -0,0 +1,36 @@ +name: SonarQube +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] +jobs: + build: + name: Build and analyze + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: 17 + distribution: 'zulu' # Alternative distribution options are available. + - name: Cache SonarQube packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Build and analyze + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=pet-ads_systematic \ No newline at end of file diff --git a/pom.xml b/pom.xml index da369b719..693dbddf5 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,8 @@ official 1.8 1.9.0 + pet-ads + https://sonarcloud.io From 889a36530a080ece269bf8e0adbdc4605ef4d79a Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sat, 21 Jun 2025 16:13:54 -0300 Subject: [PATCH 057/153] chore(jpa): remove explicit Hibernate dialect configuration --- web/src/main/resources/application.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/main/resources/application.yaml b/web/src/main/resources/application.yaml index d5956b6bc..6e9a2abe7 100644 --- a/web/src/main/resources/application.yaml +++ b/web/src/main/resources/application.yaml @@ -21,7 +21,6 @@ spring: properties: hibernate: format_sql: true - database-platform: org.hibernate.dialect.PostgreSQLDialect jwt: key: "dasdasdadadasdasdadadasdasdadadasdasdadadasdasdada" From a2b0078ab507e361b2859593f66735976d1213bb Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sat, 21 Jun 2025 16:14:45 -0300 Subject: [PATCH 058/153] chore(deps): bump springdoc-openapi-starter-webmvc-ui to 2.8.9 and swagger-annotations to 2.2.31 --- review/pom.xml | 4 ++-- web/pom.xml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/review/pom.xml b/review/pom.xml index 5d782b870..920d13193 100644 --- a/review/pom.xml +++ b/review/pom.xml @@ -32,11 +32,11 @@ 1.0-SNAPSHOT compile + io.swagger.core.v3 swagger-annotations-jakarta - 2.2.19 - compile + 2.2.31 org.apache.commons diff --git a/web/pom.xml b/web/pom.xml index 588d0e033..5a2c513f7 100644 --- a/web/pom.xml +++ b/web/pom.xml @@ -38,10 +38,11 @@ org.springframework.boot spring-boot-starter-web + org.springdoc springdoc-openapi-starter-webmvc-ui - 2.3.0 + 2.8.9 org.springframework.boot From 34be8564ff60c4d3ff5874e5ece90b73733a1a40 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sat, 21 Jun 2025 22:09:53 -0300 Subject: [PATCH 059/153] chore: delete bogus unused file --- test-actions.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test-actions.txt diff --git a/test-actions.txt b/test-actions.txt deleted file mode 100644 index 0d133db18..000000000 --- a/test-actions.txt +++ /dev/null @@ -1 +0,0 @@ -joão \ No newline at end of file From bc13df23a89b1b6ce9eedbc45dd04ce831f60b8a Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sat, 21 Jun 2025 22:10:12 -0300 Subject: [PATCH 060/153] feat: add links to each search source --- .../presenter/RestfulFindAllStudyReviewsPresenter.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/web/src/main/kotlin/br/all/study/presenter/RestfulFindAllStudyReviewsPresenter.kt b/web/src/main/kotlin/br/all/study/presenter/RestfulFindAllStudyReviewsPresenter.kt index 16b363b89..6aab812d7 100644 --- a/web/src/main/kotlin/br/all/study/presenter/RestfulFindAllStudyReviewsPresenter.kt +++ b/web/src/main/kotlin/br/all/study/presenter/RestfulFindAllStudyReviewsPresenter.kt @@ -4,11 +4,8 @@ import br.all.application.study.find.presenter.FindAllStudyReviewsPresenter import br.all.application.study.find.service.FindAllStudyReviewsService.ResponseModel import br.all.application.study.repository.StudyReviewDto import br.all.shared.error.createErrorResponseFrom -import br.all.study.controller.StudyReviewController -import br.all.study.requests.PostStudyReviewRequest import br.all.utils.LinksFactory import org.springframework.hateoas.RepresentationModel -import org.springframework.hateoas.server.mvc.linkTo import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.stereotype.Component @@ -25,10 +22,13 @@ class RestfulFindAllStudyReviewsPresenter( val restfulResponse = ViewModel(response.systematicStudyId, response.studyReviews.size, response.studyReviews) val selfRef = linksFactory.findAllStudies(response.systematicStudyId) - val allBySource = linksFactory.findAllStudiesBySource(response.systematicStudyId, "") + val sources = getSources(response.studyReviews) + for (source in sources) { + restfulResponse.add(linksFactory.findAllStudiesBySource(response.systematicStudyId, source)) + } val createStudyReview = linksFactory.createStudy(response.systematicStudyId) - restfulResponse.add(selfRef, allBySource, createStudyReview) + restfulResponse.add(selfRef, createStudyReview) responseEntity = ResponseEntity.status(HttpStatus.OK).body(restfulResponse) } @@ -36,6 +36,8 @@ class RestfulFindAllStudyReviewsPresenter( override fun isDone() = responseEntity != null + fun getSources(studies: List): List = studies.flatMap { it.searchSources }.distinct() + private data class ViewModel ( val systematicStudyId : UUID, val size: Int, From b4db5855ef9fd22aa7fef39ee8e2b42e167f6c13 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 22 Jun 2025 01:26:20 -0300 Subject: [PATCH 061/153] feat: change owner back to researcherId --- .../CreateSystematicStudyServiceImpl.kt | 22 ++++++++++-- .../repository/SystematicStudyMapper.kt | 7 ++-- .../model/collaboration/Collaboration.kt | 35 +++++++++++-------- .../domain/model/review/SystematicStudy.kt | 28 ++++++++------- .../SystematicStudyServicesConfiguration.kt | 3 ++ 5 files changed, 63 insertions(+), 32 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImpl.kt b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImpl.kt index d0281b996..9a11a4742 100644 --- a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.review.create +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDto import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.repository.toDto import br.all.application.user.CredentialsService @@ -9,9 +11,14 @@ import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromRequestModel import br.all.application.review.repository.toDto import br.all.application.shared.presenter.prepareIfUnauthorized +import br.all.domain.model.collaboration.Collaboration +import br.all.domain.model.collaboration.CollaborationId +import br.all.domain.model.collaboration.CollaborationPermission +import br.all.domain.model.collaboration.toCollaborationId import br.all.domain.model.protocol.Protocol import br.all.domain.model.review.SystematicStudy import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.ResearcherId import br.all.domain.services.UuidGeneratorService class CreateSystematicStudyServiceImpl( @@ -19,6 +26,7 @@ class CreateSystematicStudyServiceImpl( private val protocolRepository: ProtocolRepository, private val uuidGeneratorService: UuidGeneratorService, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : CreateSystematicStudyService { override fun create(presenter: CreateSystematicStudyPresenter, request: RequestModel) { @@ -28,12 +36,22 @@ class CreateSystematicStudyServiceImpl( if (presenter.isDone()) return val generatedId = uuidGeneratorService.next() - val systematicStudy = SystematicStudy.fromRequestModel(generatedId, request) + val collabId = uuidGeneratorService.next() + + val ownerCollaboration = Collaboration( + collabId.toCollaborationId(), + generatedId.toSystematicStudyId(), + user!!.id as ResearcherId, + permissions = setOf(CollaborationPermission.VIEW, CollaborationPermission.EDIT, CollaborationPermission.REVIEW_STUDIES) + ) + collaborationRepository.saveOrUpdateCollaboration(ownerCollaboration.toDto()) + + val systematicStudy = SystematicStudy.fromRequestModel(generatedId, request, ownerCollaboration.id as CollaborationId) systematicStudyRepository.saveOrUpdate(systematicStudy.toDto()) val protocol = Protocol.write(generatedId.toSystematicStudyId(), emptySet()).build() protocolRepository.saveOrUpdate(protocol.toDto()) - presenter.prepareSuccessView(ResponseModel(user!!.id.value(), generatedId)) + presenter.prepareSuccessView(ResponseModel(user.id.value(), generatedId)) } } diff --git a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt index 462508aa0..c5156a551 100644 --- a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt +++ b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt @@ -15,18 +15,19 @@ fun SystematicStudy.toDto() = SystematicStudyDto( collaborators.map { it.value }.toSet(), ) -fun SystematicStudy.Companion.fromRequestModel(id: UUID, requestModel: RequestModel) = SystematicStudy( +fun SystematicStudy.Companion.fromRequestModel(id: UUID, requestModel: RequestModel, ownerCollaborationId: CollaborationId) = SystematicStudy( SystematicStudyId(id), requestModel.title, requestModel.description, - CollaborationId(requestModel.userId), + ResearcherId(requestModel.userId), + setOf(ownerCollaborationId) ) fun SystematicStudy.Companion.fromDto(dto: SystematicStudyDto) = SystematicStudy( SystematicStudyId(dto.id), dto.title, dto.description, - CollaborationId(dto.owner), + ResearcherId(dto.owner), dto.collaborators .map { CollaborationId(it) } .toMutableSet(), diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index cc11c61e0..2f9df8507 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -12,29 +12,34 @@ class Collaboration( val userId: ResearcherId, status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() - ): Entity(id) { - - init{ - val notification = validate() - require(notification.hasNoErrors()) { notification.message() } - } - +) : Entity(id) { + private val _permissions = permissions.toMutableSet() - val permissions get() = _permissions - + val permissions: Set + get() = _permissions.toSet() + var status = status private set + + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } - fun addPermission(permission: CollaborationPermission) = _permissions.add(permission) - - fun removePermission(permission: CollaborationPermission) = _permissions.remove(permission) + fun addPermission(permission: CollaborationPermission) { + _permissions.add(permission) + } + + fun removePermission(permission: CollaborationPermission) { + _permissions.remove(permission) + } fun removeCollaboration() { status = CollaborationStatus.REMOVED } - - private fun validate() = Notification().also{ - if(permissions.isEmpty()) + + private fun validate() = Notification().also { + if (_permissions.isEmpty()) it.addError("Collaboration must have at least one permission") } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt index f4efb9c97..d6041339c 100644 --- a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt +++ b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt @@ -1,6 +1,10 @@ package br.all.domain.model.review +import br.all.domain.model.collaboration.Collaboration import br.all.domain.model.collaboration.CollaborationId +import br.all.domain.model.collaboration.toCollaborationId +import br.all.domain.model.user.ResearcherId +import br.all.domain.model.user.toResearcherId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification import br.all.domain.shared.utils.exists @@ -10,8 +14,8 @@ class SystematicStudy( id: SystematicStudyId, title: String, description: String, - owner: CollaborationId, - collaborators: Set = emptySet(), + owner: ResearcherId, + collaborators: Set ) : Entity(id) { private val _collaborators = collaborators.toMutableSet() @@ -32,7 +36,6 @@ class SystematicStudy( init { val notification = validate() require(notification.hasNoErrors()) { notification.message() } - _collaborators.add(owner) } private fun validate() = Notification().also { @@ -44,17 +47,18 @@ class SystematicStudy( fun addCollaborator(collaborationId: CollaborationId) = _collaborators.add(collaborationId) - fun changeOwner(collaborationId: CollaborationId) { - _collaborators.add(collaborationId) - owner = collaborationId - } + fun changeOwner(previousOwnerCollaborationId: CollaborationId, newCollaboration: Collaboration) { + _collaborators.remove(previousOwnerCollaborationId) + owner = newCollaboration.userId + _collaborators.add(newCollaboration.id as CollaborationId) + } - fun removeCollaborator(collaborationId: CollaborationId) { - check(collaborationId != owner) { "Cannot remove the Systematic Study owner: $owner" } - exists(collaborationId in _collaborators) { - "Cannot remove member that is not part of the collaboration: $collaborationId" + fun removeCollaborator(collaboration: Collaboration) { + check(collaboration.id.value().toResearcherId() != owner) { "Cannot remove the Systematic Study owner: $owner" } + exists(collaboration.id.value().toCollaborationId() in _collaborators) { + "Cannot remove member that is not part of the collaboration: ${collaboration.id}" } - _collaborators.remove(collaborationId) + _collaborators.remove(collaboration.id) } override fun toString() = "SystematicStudy(reviewId=$id, title='$title', description='$description', owner=$owner," + diff --git a/web/src/main/kotlin/br/all/review/controller/SystematicStudyServicesConfiguration.kt b/web/src/main/kotlin/br/all/review/controller/SystematicStudyServicesConfiguration.kt index 61335937e..cfa3c20d8 100644 --- a/web/src/main/kotlin/br/all/review/controller/SystematicStudyServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/review/controller/SystematicStudyServicesConfiguration.kt @@ -1,5 +1,6 @@ package br.all.review.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.user.CredentialsService import br.all.application.review.create.CreateSystematicStudyServiceImpl @@ -19,11 +20,13 @@ class SystematicStudyServicesConfiguration { protocolRepository: ProtocolRepository, uuidGeneratorService: UuidGeneratorService, credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = CreateSystematicStudyServiceImpl( systematicStudyRepository, protocolRepository, uuidGeneratorService, credentialsService, + collaborationRepository, ) @Bean From 3bf6562b965294a393a0eff4457658d664d67823 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 22 Jun 2025 01:26:39 -0300 Subject: [PATCH 062/153] test: correct tests --- .../CreateSystematicStudyServiceImplTest.kt | 9 ++- .../review/util/TestDataFactory.kt | 11 +--- .../model/review/SystematicStudyTest.kt | 59 ++++++------------- 3 files changed, 26 insertions(+), 53 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt b/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt index 14bfc6d3c..4e2f486bb 100644 --- a/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.review.create +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.util.TestDataFactory @@ -29,6 +30,8 @@ class CreateSystematicStudyServiceImplTest { private lateinit var uuidGeneratorService: UuidGeneratorService @MockK private lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository @MockK(relaxed = true) private lateinit var presenter: CreateSystematicStudyPresenter @InjectMockKs @@ -47,6 +50,8 @@ class CreateSystematicStudyServiceImplTest { factory.researcher, factory.systematicStudy ) + + every { collaborationRepository.saveOrUpdateCollaboration(any()) } returns Unit } @Nested @@ -58,7 +63,6 @@ class CreateSystematicStudyServiceImplTest { val (_, systematicStudy) = factory val request = factory.createRequestModel() val response = factory.createResponseModel() - val dto = factory.dtoFromCreateRequest(request) val protocolDto = factory.protocolDto() preconditionCheckerMocking.makeEverythingWork() @@ -67,8 +71,7 @@ class CreateSystematicStudyServiceImplTest { sut.create(presenter, request) verify(exactly = 1) { - uuidGeneratorService.next() - systematicStudyRepository.saveOrUpdate(dto) + systematicStudyRepository.saveOrUpdate(any()) protocolRepository.saveOrUpdate(protocolDto) presenter.prepareSuccessView(response) } diff --git a/review/src/test/kotlin/br/all/application/review/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/review/util/TestDataFactory.kt index fd03b3921..61039c7cf 100644 --- a/review/src/test/kotlin/br/all/application/review/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/review/util/TestDataFactory.kt @@ -6,6 +6,7 @@ import br.all.application.review.repository.SystematicStudyDto import br.all.application.review.repository.fromRequestModel import br.all.application.review.repository.toDto import br.all.application.review.update.services.UpdateSystematicStudyService.ResponseModel +import br.all.domain.model.collaboration.CollaborationId import br.all.domain.model.protocol.Protocol import br.all.domain.model.review.SystematicStudy import br.all.domain.model.review.toSystematicStudyId @@ -46,20 +47,14 @@ class TestDataFactory { fun createRequestModel( researcherId: UUID = researcher, title: String = faker.book.title(), - description: String = faker.lorem.words(), - collaborators: Set = emptySet() - ) = CreateRequestModel(researcherId, title, description, collaborators) + description: String = faker.lorem.words() + ) = CreateRequestModel(researcherId, title, description) fun createResponseModel( researcherId: UUID = researcher, systematicStudyId: UUID = systematicStudy, ) = CreateResponseModel(researcherId, systematicStudyId) - fun dtoFromCreateRequest( - request: CreateRequestModel, - systematicStudyId: UUID = systematicStudy, - ) = SystematicStudy.fromRequestModel(systematicStudyId, request).toDto() - fun findOneRequestModel( researcherId: UUID = researcher, systematicStudyId: UUID = systematicStudy, diff --git a/review/src/test/kotlin/br/all/domain/model/review/SystematicStudyTest.kt b/review/src/test/kotlin/br/all/domain/model/review/SystematicStudyTest.kt index e9e0f3e8a..d37a5f2b6 100644 --- a/review/src/test/kotlin/br/all/domain/model/review/SystematicStudyTest.kt +++ b/review/src/test/kotlin/br/all/domain/model/review/SystematicStudyTest.kt @@ -1,5 +1,8 @@ package br.all.domain.model.review +import br.all.domain.model.collaboration.Collaboration +import br.all.domain.model.collaboration.CollaborationId +import br.all.domain.model.collaboration.CollaborationPermission import br.all.domain.model.user.ResearcherId import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.* @@ -17,7 +20,7 @@ class SystematicStudyTest { fun setUp() { val systematicStudyId = SystematicStudyId(UUID.randomUUID()) val owner = ResearcherId(UUID.randomUUID()) - sut = SystematicStudy(systematicStudyId, "Some title", "Some description", owner) + sut = SystematicStudy(systematicStudyId, "Some title", "Some description", owner, setOf()) } @Nested @@ -31,19 +34,10 @@ class SystematicStudyTest { fun `should successfully create an systematic study`() { val id = SystematicStudyId(UUID.randomUUID()) val owner = ResearcherId(UUID.randomUUID()) - val collaborators = mutableSetOf(ResearcherId(UUID.randomUUID())) + val collaborators = mutableSetOf(CollaborationId(UUID.randomUUID())) assertDoesNotThrow { SystematicStudy(id, "Title", "Description", owner, collaborators) } } - - @Test - fun `should owner be a collaborator`() { - val id = SystematicStudyId(UUID.randomUUID()) - val ownerId = ResearcherId(UUID.randomUUID()) - val sut = SystematicStudy(id, "Title", "Description", ownerId, mutableSetOf()) - - assertTrue(ownerId in sut.collaborators) - } } @Nested @@ -56,7 +50,7 @@ class SystematicStudyTest { val id = SystematicStudyId(UUID.randomUUID()) val owner = ResearcherId(UUID.randomUUID()) - assertThrows { SystematicStudy(id, title, description, owner) } + assertThrows { SystematicStudy(id, title, description, owner, setOf()) } } } } @@ -64,17 +58,10 @@ class SystematicStudyTest { @Nested @DisplayName("When adding new collaborators") inner class WhenAddingNewCollaborators { - @Test - @Tag("ValidClasses") - fun `should add new collaborator`() { - sut.addCollaborator(ResearcherId(UUID.randomUUID())) - assertEquals(2, sut.collaborators.size) - } - @Test @Tag("InvalidClasses") fun `should not add duplicated researchers`() { - val duplicatedResearcher = ResearcherId(UUID.randomUUID()) + val duplicatedResearcher = CollaborationId(UUID.randomUUID()) sut.addCollaborator(duplicatedResearcher) sut.addCollaborator(duplicatedResearcher) @@ -93,12 +80,14 @@ class SystematicStudyTest { @Test fun `should remove valid collaborator`() { val researcherId = ResearcherId(UUID.randomUUID()) + val collabId = CollaborationId(UUID.randomUUID()) + val collaboration = Collaboration(collabId, sut.id as SystematicStudyId, researcherId, permissions = setOf(CollaborationPermission.VIEW)) - sut.addCollaborator(researcherId) - assertTrue(researcherId in sut.collaborators, "researcher was not even added" ) + sut.addCollaborator(collabId) + assertTrue(collabId in sut.collaborators, "researcher was not even added" ) - sut.removeCollaborator(researcherId) - assertFalse(researcherId in sut.collaborators, "researcher was not removed") + sut.removeCollaborator(collaboration) + assertFalse(collabId in sut.collaborators, "researcher was not removed") } } @@ -109,33 +98,19 @@ class SystematicStudyTest { @Test fun `should not allow removing owner from collaborators`(){ val ownerId = sut.owner - assertThrows { sut.removeCollaborator(ownerId) } + val collaboration = Collaboration(CollaborationId(UUID.randomUUID()), sut.id as SystematicStudyId, ownerId, permissions = setOf(CollaborationPermission.VIEW)) + assertThrows { sut.removeCollaborator(collaboration) } } @Test fun `should throw if try to remove absent collaborator`(){ val absentResearcher = ResearcherId(UUID.randomUUID()) - assertThrows { sut.removeCollaborator(absentResearcher) } + val collaboration = Collaboration(CollaborationId(UUID.randomUUID()), sut.id as SystematicStudyId, absentResearcher, permissions = setOf(CollaborationPermission.VIEW)) + assertThrows { sut.removeCollaborator(collaboration) } } } } - @Nested - @DisplayName("When changing the owner") - inner class WhenChangingTheOwner { - @Test - @Tag("ValidClasses") - fun `should add new owner to collaborators if not present yet`(){ - val newOwner = ResearcherId(UUID.randomUUID()) - sut.changeOwner(newOwner) - - Assertions.assertAll("change owner", - { assertTrue(newOwner in sut.collaborators) }, - { assertEquals(sut.owner, newOwner) } - ) - } - } - @Nested @DisplayName("When changing the title") inner class WhenChangingTheTitle { From e19dcb76734e511284cb20a3f2fa59997e72048b Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:27:18 -0300 Subject: [PATCH 063/153] feat: add link to RemoveCriteriaService --- web/src/main/kotlin/br/all/utils/LinksFactory.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/src/main/kotlin/br/all/utils/LinksFactory.kt b/web/src/main/kotlin/br/all/utils/LinksFactory.kt index dcea9b1fe..205d590f6 100644 --- a/web/src/main/kotlin/br/all/utils/LinksFactory.kt +++ b/web/src/main/kotlin/br/all/utils/LinksFactory.kt @@ -12,6 +12,7 @@ import br.all.study.controller.StudyReviewController import br.all.study.requests.PatchDuplicatedStudiesRequest import br.all.study.requests.PatchStatusStudyReviewRequest import br.all.study.requests.PostStudyReviewRequest +import br.all.study.requests.RemoveCriteriaRequest import org.springframework.hateoas.Link import org.springframework.hateoas.server.mvc.linkTo import org.springframework.stereotype.Component @@ -324,4 +325,13 @@ class LinksFactory { studyReviewId ) }.withRel("find-study-criteria").withType("GET") + + fun removeStudyReviewCriteria(systematicStudyId: UUID, studyReviewId: Long, request: RemoveCriteriaRequest): Link = + linkTo { + removeCriterion( + systematicStudyId, + studyReviewId, + request + ) + }.withRel("remove-criteria").withType("PATCH") } From b82d735626c6801320c89422fe11b9155078ef62 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:27:34 -0300 Subject: [PATCH 064/153] feat: create remove criteria presenter --- .../study/update/interfaces/RemoveCriteriaPresenter.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaPresenter.kt diff --git a/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaPresenter.kt b/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaPresenter.kt new file mode 100644 index 000000000..ab24adad1 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaPresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.study.update.interfaces + +import br.all.application.shared.presenter.GenericPresenter + + +interface RemoveCriteriaPresenter: GenericPresenter \ No newline at end of file From b7b2b5339088bd4c23f89809a76c6258041792c1 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:27:41 -0300 Subject: [PATCH 065/153] feat: create remove criteria request --- .../all/study/requests/RemoveCriteriaRequest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 web/src/main/kotlin/br/all/study/requests/RemoveCriteriaRequest.kt diff --git a/web/src/main/kotlin/br/all/study/requests/RemoveCriteriaRequest.kt b/web/src/main/kotlin/br/all/study/requests/RemoveCriteriaRequest.kt new file mode 100644 index 000000000..391995f94 --- /dev/null +++ b/web/src/main/kotlin/br/all/study/requests/RemoveCriteriaRequest.kt @@ -0,0 +1,15 @@ +package br.all.study.requests + +import br.all.application.study.update.interfaces.RemoveCriteriaService +import java.util.* + +data class RemoveCriteriaRequest ( + val criteria: List, +) { + fun toRequestModel(userId: UUID, systematicStudyId: UUID, studyReviewId: Long) = RemoveCriteriaService.RequestModel ( + userId, + systematicStudyId, + studyReviewId, + criteria + ) +} From 267d5613f0544f3c7b31480cb22729867701c402 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:27:49 -0300 Subject: [PATCH 066/153] feat: create remove criteria service --- .../interfaces/RemoveCriteriaService.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaService.kt diff --git a/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaService.kt b/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaService.kt new file mode 100644 index 000000000..1f4923842 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/interfaces/RemoveCriteriaService.kt @@ -0,0 +1,22 @@ +package br.all.application.study.update.interfaces + +import java.util.* + + +interface RemoveCriteriaService { + fun removeCriteria(presenter: RemoveCriteriaPresenter, request: RequestModel) + + data class RequestModel( + val userId: UUID, + val systematicStudyId: UUID, + val studyId: Long, + val criteria: List + ) + + data class ResponseModel( + val systematicStudyId: UUID, + val studyId: Long, + val inclusionCriteria: List, + val exclusionCriteria: List, + ) +} From 8f39a3ec2043fb03379585bcd5570156effe28ff Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:27:56 -0300 Subject: [PATCH 067/153] feat: create remove criteria service impl --- .../RemoveCriteriaServiceImpl.kt | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt new file mode 100644 index 000000000..986bf2327 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt @@ -0,0 +1,70 @@ +package br.all.application.study.update.implementation + +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.exceptions.EntityNotFoundException +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.study.repository.StudyReviewRepository +import br.all.application.study.repository.fromDto +import br.all.application.study.repository.toDto +import br.all.application.study.update.interfaces.RemoveCriteriaPresenter +import br.all.application.study.update.interfaces.RemoveCriteriaService +import br.all.application.user.CredentialsService +import br.all.domain.model.protocol.Criterion +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.study.StudyReview + +class RemoveCriteriaServiceImpl( + private val studyReviewRepository: StudyReviewRepository, + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, +): RemoveCriteriaService { + override fun removeCriteria(presenter: RemoveCriteriaPresenter, request: RemoveCriteriaService.RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + if (presenter.isDone()) return + + val studyReviewDto = studyReviewRepository.findById(request.systematicStudyId, request.studyId) + if (studyReviewDto == null) { + presenter.prepareFailView( + EntityNotFoundException("Study review of id ${request.systematicStudyId} not found.") + ) + return + } + + val studyReview = StudyReview.fromDto(studyReviewDto) + + val inclusionCriteria: List = studyReview.criteria + .filter { it.type == Criterion.CriterionType.INCLUSION } + .map { it.description } + + val exclusionCriteria: List = studyReview.criteria + .filter { it.type == Criterion.CriterionType.EXCLUSION } + .map { it.description } + + request.criteria + .filter { it.isNotBlank() } + .forEach { criterionString -> + studyReview.criteria + .filter { it.description == criterionString } + .forEach { matching -> + studyReview.removeCriterion(matching) + } + } + + studyReviewRepository.saveOrUpdate(studyReview.toDto()) + + presenter.prepareSuccessView( + RemoveCriteriaService.ResponseModel( + request.systematicStudyId, + request.studyId, + inclusionCriteria, + exclusionCriteria, + ) + ) + } +} \ No newline at end of file From e15aea4f597d3ce4de32acff3eda9480ab544836 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:28:08 -0300 Subject: [PATCH 068/153] feat: create remove criteria restful presenter --- .../RestfulRemoveCriteriaPresenter.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 web/src/main/kotlin/br/all/study/presenter/RestfulRemoveCriteriaPresenter.kt diff --git a/web/src/main/kotlin/br/all/study/presenter/RestfulRemoveCriteriaPresenter.kt b/web/src/main/kotlin/br/all/study/presenter/RestfulRemoveCriteriaPresenter.kt new file mode 100644 index 000000000..438284947 --- /dev/null +++ b/web/src/main/kotlin/br/all/study/presenter/RestfulRemoveCriteriaPresenter.kt @@ -0,0 +1,60 @@ +package br.all.study.presenter + +import br.all.application.study.update.interfaces.RemoveCriteriaPresenter +import br.all.application.study.update.interfaces.RemoveCriteriaService +import br.all.shared.error.createErrorResponseFrom +import br.all.study.requests.RemoveCriteriaRequest +import br.all.utils.LinksFactory +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity + +class RestfulRemoveCriteriaPresenter( + private val linksFactory: LinksFactory, +): RemoveCriteriaPresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: RemoveCriteriaService.ResponseModel) { + val restfulResponse = ViewModel( + response.inclusionCriteria, + response.exclusionCriteria, + ) + + response.inclusionCriteria.forEach { + restfulResponse.add(linksFactory.removeStudyReviewCriteria + ( + response.systematicStudyId, + response.studyId, + RemoveCriteriaRequest( + criteria = listOf(it) + ) + ) + ) + } + + response.exclusionCriteria.forEach { + restfulResponse.add(linksFactory.removeStudyReviewCriteria + ( + response.systematicStudyId, + response.studyId, + RemoveCriteriaRequest( + criteria = listOf(it) + ) + ) + ) + } + + val protocol = linksFactory.findProtocol(response.systematicStudyId) + restfulResponse.add(protocol) + responseEntity = ResponseEntity.status(HttpStatus.OK).body(restfulResponse) + } + + override fun prepareFailView(throwable: Throwable) = run {responseEntity = createErrorResponseFrom(throwable) } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val inclusionCriteria: List, + val exclusionCriteria: List, + ) : RepresentationModel() +} \ No newline at end of file From 6f7dd6a7c0649cec985c43e803fb4d780d06b504 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:28:30 -0300 Subject: [PATCH 069/153] feat: create remove criteria request mapping --- .../study/controller/StudyReviewController.kt | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt b/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt index 11670b2ba..01bc6a7c8 100644 --- a/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt +++ b/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt @@ -35,6 +35,7 @@ class StudyReviewController( private val updateSelectionService: UpdateStudyReviewSelectionService, private val updateExtractionService: UpdateStudyReviewExtractionService, private val updateReadingPriorityService: UpdateStudyReviewPriorityService, + private val removeCriteriaService: RemoveCriteriaService, private val markAsDuplicatedService: MarkAsDuplicatedService, private val answerQuestionService: AnswerQuestionService, private val authenticationInfoService: AuthenticationInfoService, @@ -481,4 +482,39 @@ class StudyReviewController( markAsDuplicatedService.markAsDuplicated(presenter, request) return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) } + + @PatchMapping("/study-review/remove-criteria/{studyReviewId}") + @Operation(summary = "Remove a criteria from study review") + @ApiResponses( + value = [ + ApiResponse(responseCode = "200", description = "Success removing criteria of study review", + content = [Content(schema = Schema(hidden = true))]), + ApiResponse( + responseCode = "400", + description = "Fail removing criteria of study review - invalid status", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "401", + description = "Fail removing criteria of study review - unauthenticated user", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "403", + description = "Fail removing criteria of study review - unauthorized user", + content = [Content(schema = Schema(hidden = true))] + ), + ] + ) + fun removeCriterion( + @PathVariable systematicStudy: UUID, + @PathVariable studyReviewId: Long, + @RequestBody patchRequest: RemoveCriteriaRequest + ): ResponseEntity<*> { + val presenter = RestfulRemoveCriteriaPresenter(linksFactory) + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = patchRequest.toRequestModel(userId, systematicStudy, studyReviewId) + removeCriteriaService.removeCriteria(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } } \ No newline at end of file From bcad4b2f43c4ebf7abb481f518f63ecd6800b507 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Sun, 22 Jun 2025 03:28:46 -0300 Subject: [PATCH 070/153] feat: add remove criteria service config --- .../controller/StudyReviewServicesConfiguration.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt index 4c89d9144..95ff740fd 100644 --- a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt @@ -138,4 +138,15 @@ class StudyReviewServicesConfiguration { systematicStudyRepository, credentialsService ) + + @Bean + fun removeCriteriaService( + studyReviewRepository: StudyReviewRepository, + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService, + ) = RemoveCriteriaServiceImpl( + studyReviewRepository, + systematicStudyRepository, + credentialsService + ) } \ No newline at end of file From 59646a38c34992e9c2c0feb530f2024abdd85f3f Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 23 Jun 2025 15:10:16 -0300 Subject: [PATCH 071/153] chore: remove junit dependency - let spring solve it automatically --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 693dbddf5..b98537552 100644 --- a/pom.xml +++ b/pom.xml @@ -69,12 +69,6 @@ kotlin-faker 1.15.0 - - org.junit.jupiter - junit-jupiter-engine - 5.8.2 - test - com.tngtech.archunit archunit-junit5 From 8c6b4406979ec59067f9d5918c469aa96dadc85c Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 23 Jun 2025 15:32:20 -0300 Subject: [PATCH 072/153] build: normalise scas kotlin version --- scas/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scas/pom.xml b/scas/pom.xml index 14a1e5fb8..b8ddb39a2 100644 --- a/scas/pom.xml +++ b/scas/pom.xml @@ -81,7 +81,7 @@ org.jetbrains.kotlin kotlin-stdlib - 1.9.23 + 1.9.0 br.all From 974506dfec44150a4c53f5744bfc3481361d67e6 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Tue, 24 Jun 2025 14:22:35 -0300 Subject: [PATCH 073/153] chore: change text to be grammatically accurate. --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index b98537552..a2365f4e1 100644 --- a/pom.xml +++ b/pom.xml @@ -155,9 +155,9 @@ - This was the old executions property, it was removed because, as indicated by the kotlin docs, - from version 1.8.2 you can replace all of it with: true. This is a faulty - executions property, it is here only for eventual future reference. + This was the old executions configuration; it has been removed because, as indicated by the Kotlin docs, from version 1.8.2 onward you can replace all of it with: + true + This executions block is faulty and is included here only for eventual future reference. --> true From a95e7558728d8dcaaea3d74f54df50f9c925d2ef Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 14:50:11 -0300 Subject: [PATCH 074/153] feat(batchAnswer): add new patch batch request model --- ...chBatchAnswerQuestionStudyReviewRequest.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 web/src/main/kotlin/br/all/study/requests/PatchBatchAnswerQuestionStudyReviewRequest.kt diff --git a/web/src/main/kotlin/br/all/study/requests/PatchBatchAnswerQuestionStudyReviewRequest.kt b/web/src/main/kotlin/br/all/study/requests/PatchBatchAnswerQuestionStudyReviewRequest.kt new file mode 100644 index 000000000..110711493 --- /dev/null +++ b/web/src/main/kotlin/br/all/study/requests/PatchBatchAnswerQuestionStudyReviewRequest.kt @@ -0,0 +1,34 @@ +package br.all.study.requests + +import br.all.application.study.update.interfaces.BatchAnswerQuestionService +import java.util.UUID + +class PatchBatchAnswerQuestionStudyReviewRequest( + val answers: List +) { + data class AnswerPayload( + val questionId: UUID, + val type: String, + val answer: Any + ) + + fun toRequestModel(userId: UUID, + systematicStudyId: UUID, + studyReviewId: Long + ): BatchAnswerQuestionService.RequestModel { + val serviceAnswers = this.answers.map { + BatchAnswerQuestionService.RequestModel.AnswerDetail( + questionId = it.questionId, + type = it.type, + answer = it.answer + ) + } + + return BatchAnswerQuestionService.RequestModel( + userId = userId, + systematicStudyId = systematicStudyId, + studyReviewId = studyReviewId, + answers = serviceAnswers + ) + } +} \ No newline at end of file From 5e1d297327bdc15594c1e776e50c680237267618 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 14:50:30 -0300 Subject: [PATCH 075/153] feat(batchAnswer): add new patch batch service and presenter interfaces --- .../BatchAnswerQuestionPresenter.kt | 6 ++++ .../interfaces/BatchAnswerQuestionService.kt | 29 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionPresenter.kt create mode 100644 review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt diff --git a/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionPresenter.kt b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionPresenter.kt new file mode 100644 index 000000000..627d35bb8 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionPresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.study.update.interfaces + +import br.all.application.shared.presenter.GenericPresenter +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.ResponseModel + +interface BatchAnswerQuestionPresenter: GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt new file mode 100644 index 000000000..1df16e4dc --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt @@ -0,0 +1,29 @@ +package br.all.application.study.update.interfaces + +import io.swagger.v3.oas.annotations.media.Schema +import java.util.UUID + +interface BatchAnswerQuestionService { + fun batchAnswerQuestion(presenter: BatchAnswerQuestionPresenter, request: RequestModel, context: String) + + data class RequestModel( + val userId: UUID, + val systematicStudyId: UUID, + val studyReviewId: Long, + val answers: List + ) { + data class AnswerDetail( + val questionId: UUID, + val type: String, + val answer: Any + ) + } + + @Schema(name = "BatchAnswerQuestionServiceResponseModel") + data class ResponseModel( + val userId: UUID, + val systematicStudyId: UUID, + val studyReviewId: Long, + val answersProcessed: Int + ) +} \ No newline at end of file From 492e3b2b67bcf7e7be3bd8e4b557965ab1544ad8 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 14:50:37 -0300 Subject: [PATCH 076/153] feat(batchAnswer): add new patch batch service implementation --- .../BatchAnswerQuestionServiceImpl.kt | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt new file mode 100644 index 000000000..73f035848 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -0,0 +1,115 @@ +package br.all.application.study.update.implementation + +import br.all.application.question.repository.QuestionRepository +import br.all.application.question.repository.fromDto +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.exceptions.EntityNotFoundException +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.study.repository.StudyReviewRepository +import br.all.application.study.repository.fromDto +import br.all.application.study.repository.toDto +import br.all.application.study.update.interfaces.BatchAnswerQuestionPresenter +import br.all.application.study.update.interfaces.BatchAnswerQuestionService +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.RequestModel +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.ResponseModel +import br.all.application.user.CredentialsService +import br.all.domain.model.question.Label +import br.all.domain.model.question.LabeledScale +import br.all.domain.model.question.NumberScale +import br.all.domain.model.question.PickList +import br.all.domain.model.question.Question +import br.all.domain.model.question.QuestionContextEnum +import br.all.domain.model.question.Textual +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.study.Answer +import br.all.domain.model.study.StudyReview + +class BatchAnswerQuestionServiceImpl( + private val studyReviewRepository: StudyReviewRepository, + private val questionRepository: QuestionRepository, + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, +): BatchAnswerQuestionService { + override fun batchAnswerQuestion( + presenter: BatchAnswerQuestionPresenter, + request: RequestModel, + context: String + ) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + if (presenter.isDone()) return + + val reviewDto = studyReviewRepository.findById(request.systematicStudyId, request.studyReviewId) + if (reviewDto == null) { + val message = "Review with id ${request.studyReviewId} in systematic study ${request.systematicStudyId} does not exist!" + presenter.prepareFailView(EntityNotFoundException(message)) + return + } + + val review = StudyReview.fromDto(reviewDto) + var answersProcessed = 0 + + for (answerDetail in request.answers) { + val questionDto = questionRepository.findById(request.systematicStudyId, answerDetail.questionId) + + if (questionDto == null) continue + if (QuestionContextEnum.valueOf(context) != questionDto.context) continue + + try { + val question = Question.fromDto(questionDto) + val answer = convertAnswer(answerDetail.type, answerDetail.answer, question) + + if (questionDto.context == QuestionContextEnum.ROB) { + review.answerQualityQuestionOf(answer) + } else { + review.answerFormQuestionOf(answer) + } + + answersProcessed++ + } catch (e: Exception) { + continue + } + } + + studyReviewRepository.saveOrUpdate(review.toDto()) + + presenter.prepareSuccessView( + ResponseModel( + request.userId, + request.systematicStudyId, + request.studyReviewId, + answersProcessed + ) + ) + } + + private fun convertAnswer( + type: String, + rawAnswer: Any, + question: Question<*> + ): Answer<*> { + return when { + type == "TEXTUAL" && rawAnswer is String -> (question as Textual).answer(rawAnswer) + type == "PICK_LIST" && rawAnswer is String -> (question as PickList).answer(rawAnswer) + type == "NUMBERED_SCALE" && rawAnswer is Int -> (question as NumberScale).answer(rawAnswer) + type == "LABELED_SCALE" -> { + when (rawAnswer) { + is Map<*, *> -> { + val name = rawAnswer["name"] as? String + val value = rawAnswer["value"] as? Int + if (name != null && value != null) { + (question as LabeledScale).answer(Label(name, value)) + } else throw IllegalArgumentException("Invalid labeled scale answer") + } + else -> throw IllegalArgumentException("Unsupported LABELED_SCALE format") + } + } + else -> throw IllegalArgumentException("Unsupported answer type or mismatched value") + } + } +} \ No newline at end of file From ab43577fbf5f5872cb24b3130026b190a083689e Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:32:11 -0300 Subject: [PATCH 077/153] refactor(batchAnswer): add properly exceptions to sad paths --- .../BatchAnswerQuestionServiceImpl.kt | 81 ++++++++++++------- .../interfaces/BatchAnswerQuestionService.kt | 14 +++- 2 files changed, 65 insertions(+), 30 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt index 73f035848..f4f1421ff 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -12,7 +12,10 @@ import br.all.application.study.repository.toDto import br.all.application.study.update.interfaces.BatchAnswerQuestionPresenter import br.all.application.study.update.interfaces.BatchAnswerQuestionService import br.all.application.study.update.interfaces.BatchAnswerQuestionService.RequestModel +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.RequestModel.AnswerDetail import br.all.application.study.update.interfaces.BatchAnswerQuestionService.ResponseModel +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.FailedAnswer +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.LabelDto import br.all.application.user.CredentialsService import br.all.domain.model.question.Label import br.all.domain.model.question.LabeledScale @@ -24,6 +27,7 @@ import br.all.domain.model.question.Textual import br.all.domain.model.review.SystematicStudy import br.all.domain.model.study.Answer import br.all.domain.model.study.StudyReview +import java.util.UUID class BatchAnswerQuestionServiceImpl( private val studyReviewRepository: StudyReviewRepository, @@ -50,29 +54,38 @@ class BatchAnswerQuestionServiceImpl( presenter.prepareFailView(EntityNotFoundException(message)) return } - val review = StudyReview.fromDto(reviewDto) - var answersProcessed = 0 + + val questionContext = QuestionContextEnum.valueOf(context.uppercase()) + val successfulQuestionIds = mutableListOf() + val failedAnswers = mutableListOf() + var totalAnswered = 0 for (answerDetail in request.answers) { - val questionDto = questionRepository.findById(request.systematicStudyId, answerDetail.questionId) + try { + val questionDto = questionRepository.findById(request.systematicStudyId, answerDetail.questionId) - if (questionDto == null) continue - if (QuestionContextEnum.valueOf(context) != questionDto.context) continue + if (questionDto == null) throw EntityNotFoundException("Question with id ${answerDetail.questionId} in systematic study ${request.systematicStudyId} was not found!") + if (questionDto.context != questionContext) throw IllegalArgumentException("Should answer question with the context: $context, found: ${questionDto.context}") - try { val question = Question.fromDto(questionDto) - val answer = convertAnswer(answerDetail.type, answerDetail.answer, question) + val answer = convertAnswer(question, answerDetail, questionDto.context.name) - if (questionDto.context == QuestionContextEnum.ROB) { + if (questionContext == QuestionContextEnum.ROB) { review.answerQualityQuestionOf(answer) } else { review.answerFormQuestionOf(answer) } - answersProcessed++ + successfulQuestionIds.add(answerDetail.questionId) + totalAnswered++ } catch (e: Exception) { - continue + failedAnswers.add( + FailedAnswer( + questionId = answerDetail.questionId, + reason = e.message ?: "An unknown error occurred!" + ) + ) } } @@ -80,36 +93,46 @@ class BatchAnswerQuestionServiceImpl( presenter.prepareSuccessView( ResponseModel( - request.userId, - request.systematicStudyId, - request.studyReviewId, - answersProcessed + userId = request.userId, + systematicStudyId = request.systematicStudyId, + studyReviewId = request.studyReviewId, + succeededAnswers = successfulQuestionIds, + failedAnswers = failedAnswers, + totalAnswered = totalAnswered ) ) } private fun convertAnswer( - type: String, - rawAnswer: Any, - question: Question<*> + question: Question<*>, + detail: AnswerDetail, + type: String ): Answer<*> { + if (detail.type != type) { + throw IllegalArgumentException("Type mismatch: Request payload type is '${detail.type}', but question ${question.id} is of type '${type}'") + } return when { - type == "TEXTUAL" && rawAnswer is String -> (question as Textual).answer(rawAnswer) - type == "PICK_LIST" && rawAnswer is String -> (question as PickList).answer(rawAnswer) - type == "NUMBERED_SCALE" && rawAnswer is Int -> (question as NumberScale).answer(rawAnswer) + type == "TEXTUAL" && detail.answer is String -> (question as Textual).answer(detail.answer) + type == "PICK_LIST" && detail.answer is String -> (question as PickList).answer(detail.answer) + type == "NUMBERED_SCALE" && detail.answer is Int -> (question as NumberScale).answer(detail.answer) type == "LABELED_SCALE" -> { - when (rawAnswer) { - is Map<*, *> -> { - val name = rawAnswer["name"] as? String - val value = rawAnswer["value"] as? Int - if (name != null && value != null) { - (question as LabeledScale).answer(Label(name, value)) - } else throw IllegalArgumentException("Invalid labeled scale answer") + when (val answer = detail.answer) { + is LinkedHashMap<*, *> -> { + (answer["name"] as? String)?.let { name -> + (answer["value"] as? Int)?.let { value -> + (question as LabeledScale).answer(Label(name, value)) + } + } ?: throw IllegalArgumentException("Invalid labeled scale answer: missing 'name' or 'value'") + } + is LabelDto -> { + (question as LabeledScale).answer(Label(answer.name, answer.value)) + } + else -> { + throw IllegalArgumentException("Unsupported answer type for 'LABELED_SCALE'") } - else -> throw IllegalArgumentException("Unsupported LABELED_SCALE format") } } - else -> throw IllegalArgumentException("Unsupported answer type or mismatched value") + else -> throw IllegalArgumentException("Answer type of '${detail.answer.javaClass}' is not compatible with question type '${type}'") } } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt index 1df16e4dc..36c6299d1 100644 --- a/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt +++ b/review/src/main/kotlin/br/all/application/study/update/interfaces/BatchAnswerQuestionService.kt @@ -19,11 +19,23 @@ interface BatchAnswerQuestionService { ) } + data class FailedAnswer( + val questionId: UUID, + val reason: String + ) + + data class LabelDto( + val name: String, + val value: Int + ) + @Schema(name = "BatchAnswerQuestionServiceResponseModel") data class ResponseModel( val userId: UUID, val systematicStudyId: UUID, val studyReviewId: Long, - val answersProcessed: Int + val succeededAnswers: List, + val failedAnswers: List, + val totalAnswered: Int ) } \ No newline at end of file From 29ecba19f31929ce8ca10c9a6fa35ae9d3a80cda Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:35:14 -0300 Subject: [PATCH 078/153] fix(batchAnswer): change convert answer wrong passing param --- .../BatchAnswerQuestionServiceImpl.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt index f4f1421ff..1f971a240 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -69,9 +69,9 @@ class BatchAnswerQuestionServiceImpl( if (questionDto.context != questionContext) throw IllegalArgumentException("Should answer question with the context: $context, found: ${questionDto.context}") val question = Question.fromDto(questionDto) - val answer = convertAnswer(question, answerDetail, questionDto.context.name) + val answer = convertAnswer(question, answerDetail, questionDto.questionType) - if (questionContext == QuestionContextEnum.ROB) { + if (questionDto.context == QuestionContextEnum.ROB) { review.answerQualityQuestionOf(answer) } else { review.answerFormQuestionOf(answer) @@ -106,16 +106,16 @@ class BatchAnswerQuestionServiceImpl( private fun convertAnswer( question: Question<*>, detail: AnswerDetail, - type: String + questionType: String ): Answer<*> { - if (detail.type != type) { - throw IllegalArgumentException("Type mismatch: Request payload type is '${detail.type}', but question ${question.id} is of type '${type}'") + if (detail.type != questionType) { + throw IllegalArgumentException("Type mismatch: Request payload type is '${detail.type}', but question ${question.id} is of type '${questionType}'") } return when { - type == "TEXTUAL" && detail.answer is String -> (question as Textual).answer(detail.answer) - type == "PICK_LIST" && detail.answer is String -> (question as PickList).answer(detail.answer) - type == "NUMBERED_SCALE" && detail.answer is Int -> (question as NumberScale).answer(detail.answer) - type == "LABELED_SCALE" -> { + questionType == "TEXTUAL" && detail.answer is String -> (question as Textual).answer(detail.answer) + questionType == "PICK_LIST" && detail.answer is String -> (question as PickList).answer(detail.answer) + questionType == "NUMBERED_SCALE" && detail.answer is Int -> (question as NumberScale).answer(detail.answer) + questionType == "LABELED_SCALE" -> { when (val answer = detail.answer) { is LinkedHashMap<*, *> -> { (answer["name"] as? String)?.let { name -> @@ -132,7 +132,7 @@ class BatchAnswerQuestionServiceImpl( } } } - else -> throw IllegalArgumentException("Answer type of '${detail.answer.javaClass}' is not compatible with question type '${type}'") + else -> throw IllegalArgumentException("Answer type of '${detail.answer.javaClass}' is not compatible with question type '${questionType}'") } } } \ No newline at end of file From 2407d84d73e939ae3fc7e6e8f3975f54315e7f41 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:36:32 -0300 Subject: [PATCH 079/153] refactor(batchAnswer): change bloat count variable --- .../update/implementation/BatchAnswerQuestionServiceImpl.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt index 1f971a240..22c2813c9 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -59,7 +59,6 @@ class BatchAnswerQuestionServiceImpl( val questionContext = QuestionContextEnum.valueOf(context.uppercase()) val successfulQuestionIds = mutableListOf() val failedAnswers = mutableListOf() - var totalAnswered = 0 for (answerDetail in request.answers) { try { @@ -78,7 +77,6 @@ class BatchAnswerQuestionServiceImpl( } successfulQuestionIds.add(answerDetail.questionId) - totalAnswered++ } catch (e: Exception) { failedAnswers.add( FailedAnswer( @@ -98,7 +96,7 @@ class BatchAnswerQuestionServiceImpl( studyReviewId = request.studyReviewId, succeededAnswers = successfulQuestionIds, failedAnswers = failedAnswers, - totalAnswered = totalAnswered + totalAnswered = successfulQuestionIds.size ) ) } From 13fba247854031bb39a68d9d90cf97220b8e897c Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:39:41 -0300 Subject: [PATCH 080/153] fix(batchAnswer): make service implementation transactional --- .../update/implementation/BatchAnswerQuestionServiceImpl.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt index 22c2813c9..724075ecd 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -27,14 +27,19 @@ import br.all.domain.model.question.Textual import br.all.domain.model.review.SystematicStudy import br.all.domain.model.study.Answer import br.all.domain.model.study.StudyReview +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional import java.util.UUID +@Service class BatchAnswerQuestionServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val questionRepository: QuestionRepository, private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, ): BatchAnswerQuestionService { + + @Transactional override fun batchAnswerQuestion( presenter: BatchAnswerQuestionPresenter, request: RequestModel, From 2f35b2c3d170931eeae8f5afef5f519e372d9172 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:48:50 -0300 Subject: [PATCH 081/153] feat(batchAnswer): add restful batch answer question presenter --- .../RestfulBatchAnswerQuestionPresenter.kt | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 web/src/main/kotlin/br/all/study/presenter/RestfulBatchAnswerQuestionPresenter.kt diff --git a/web/src/main/kotlin/br/all/study/presenter/RestfulBatchAnswerQuestionPresenter.kt b/web/src/main/kotlin/br/all/study/presenter/RestfulBatchAnswerQuestionPresenter.kt new file mode 100644 index 000000000..7cc8f06b2 --- /dev/null +++ b/web/src/main/kotlin/br/all/study/presenter/RestfulBatchAnswerQuestionPresenter.kt @@ -0,0 +1,48 @@ +package br.all.study.presenter + +import br.all.application.study.update.interfaces.BatchAnswerQuestionPresenter +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.ResponseModel +import br.all.application.study.update.interfaces.BatchAnswerQuestionService.FailedAnswer +import br.all.shared.error.createErrorResponseFrom +import br.all.utils.LinksFactory +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.UUID + +class RestfulBatchAnswerQuestionPresenter( + private val linksFactory: LinksFactory +): BatchAnswerQuestionPresenter { + var responseEntity: ResponseEntity<*>?= null + + override fun prepareSuccessView(response: ResponseModel) { + val viewModel = ViewModel( + systematicStudyId = response.systematicStudyId, + studyReviewId = response.studyReviewId, + succeededAnswers = response.succeededAnswers, + failedAnswers = response.failedAnswers, + totalAnswered = response.totalAnswered + ) + + val link = linksFactory.findStudy(response.systematicStudyId, response.studyReviewId) + viewModel.add(link) + + responseEntity = ResponseEntity.status(HttpStatus.OK).body(viewModel) + } + + override fun prepareFailView(throwable: Throwable) { + responseEntity = createErrorResponseFrom(throwable) + } + + override fun isDone(): Boolean { + return responseEntity != null + } + + data class ViewModel( + val systematicStudyId: UUID, + val studyReviewId: Long, + val succeededAnswers: List, + val failedAnswers: List, + val totalAnswered: Int + ) : RepresentationModel() +} \ No newline at end of file From 0fd1b316195ac1a409124022eb0f439820cf3e57 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 25 Jun 2025 15:53:12 -0300 Subject: [PATCH 082/153] feat(batchAnswer): implement two new endpoints for batch answering questions --- .../study/controller/StudyReviewController.kt | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt b/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt index 01bc6a7c8..f2005b0aa 100644 --- a/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt +++ b/web/src/main/kotlin/br/all/study/controller/StudyReviewController.kt @@ -21,6 +21,9 @@ import org.springframework.web.bind.annotation.* import java.util.* import br.all.application.study.find.service.FindAllStudyReviewsBySourceService.RequestModel as FindAllBySourceRequest import br.all.application.study.find.service.FindStudyReviewService.RequestModel as FindOneRequest +import br.all.application.study.update.interfaces.BatchAnswerQuestionService +import br.all.study.presenter.RestfulBatchAnswerQuestionPresenter +import br.all.study.requests.PatchBatchAnswerQuestionStudyReviewRequest @RestController @RequestMapping("/api/v1/systematic-study/{systematicStudy}") @@ -38,6 +41,7 @@ class StudyReviewController( private val removeCriteriaService: RemoveCriteriaService, private val markAsDuplicatedService: MarkAsDuplicatedService, private val answerQuestionService: AnswerQuestionService, + private val batchAnswerQuestionService: BatchAnswerQuestionService, private val authenticationInfoService: AuthenticationInfoService, private val linksFactory: LinksFactory @@ -442,6 +446,86 @@ class StudyReviewController( return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) } + @PatchMapping("/study-review/{studyReview}/batch-riskOfBias-answers") + @Operation(summary = "Update a batch of answers for risk of bias questions") + @ApiResponses( + value = [ + ApiResponse(responseCode = "200", description = "Success updating a batch of answers to risk of bias questions", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = BatchAnswerQuestionService.ResponseModel::class) + )] + ), + ApiResponse( + responseCode = "400", + description = "Fail updating answers - invalid payload", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "401", + description = "Fail updating answers - unauthenticated user", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "403", + description = "Fail updating answers - unauthorized user", + content = [Content(schema = Schema(hidden = true))] + ), + ] + ) + fun batchRiskOfBiasAnswers( + @PathVariable systematicStudy: UUID, + @PathVariable studyReview: Long, + @RequestBody requestBody: PatchBatchAnswerQuestionStudyReviewRequest + ): ResponseEntity<*> { + val presenter = RestfulBatchAnswerQuestionPresenter(linksFactory) + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = requestBody.toRequestModel(userId, systematicStudy, studyReview) + + batchAnswerQuestionService.batchAnswerQuestion(presenter, request, "ROB") + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } + + @PatchMapping("/study-review/{studyReview}/batch-extraction-answers") + @Operation(summary = "Update a batch of answers for extraction questions") + @ApiResponses( + value = [ + ApiResponse(responseCode = "200", description = "Success updating a batch of answers to extraction questions", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = BatchAnswerQuestionService.ResponseModel::class) + )] + ), + ApiResponse( + responseCode = "400", + description = "Fail updating answers - invalid payload", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "401", + description = "Fail updating answers - unauthenticated user", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "403", + description = "Fail updating answers - unauthorized user", + content = [Content(schema = Schema(hidden = true))] + ), + ] + ) + fun batchExtractionAnswers( + @PathVariable systematicStudy: UUID, + @PathVariable studyReview: Long, + @RequestBody requestBody: PatchBatchAnswerQuestionStudyReviewRequest + ): ResponseEntity<*> { + val presenter = RestfulBatchAnswerQuestionPresenter(linksFactory) + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = requestBody.toRequestModel(userId, systematicStudy, studyReview) + + batchAnswerQuestionService.batchAnswerQuestion(presenter, request, "EXTRACTION") + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } + @PatchMapping("/study-review/{referenceStudyId}/duplicated") @Operation(summary = "Mark multiple existing studies as duplicated in the systematic study") @ApiResponses( From de1285ddfaec899fde8c8f5fd2bd5a638293ea9b Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 13:55:52 -0300 Subject: [PATCH 083/153] refactor(email): revamp email validation logic --- .../main/kotlin/br/all/domain/user/Email.kt | 59 +++++++++++-------- .../br/all/domain/shared/valueobject/Email.kt | 55 +++++++++-------- 2 files changed, 64 insertions(+), 50 deletions(-) diff --git a/account/src/main/kotlin/br/all/domain/user/Email.kt b/account/src/main/kotlin/br/all/domain/user/Email.kt index caf6dce7b..965415718 100644 --- a/account/src/main/kotlin/br/all/domain/user/Email.kt +++ b/account/src/main/kotlin/br/all/domain/user/Email.kt @@ -7,51 +7,60 @@ data class Email(val value: String) : ValueObject() { init { val notification = validate() - require(notification.hasNoErrors()) {notification.message()} + require(notification.hasNoErrors()) { notification.message() } } override fun validate(): Notification { val notification = Notification() + if (value.isEmpty()) { + notification.addError("Email must not be empty.") + return notification + } + if (value.isBlank()) { notification.addError("Email must not be blank.") return notification } + if (!isValidEmailFormat(value)) notification.addError("Wrong Email format.") + return notification } private fun isValidEmailFormat(email: String): Boolean { - if (!isValidEmailAddress(email)) return false - if (!hasLengthBelowMaximum(email)) return false - if (hasRepeatedSubdomains(email)) return false - if (email.contains("..")) return false - if (email.contains("@.")) return false - if (email.contains(".@")) return false - return true - } - - private fun isValidEmailAddress(email: String): Boolean { - val regex = Regex("^[A-Za-z0-9+_.-]+@[a-z.]+$") - return regex.matches(email) - } + if (email.contains("..") || email.contains(".@") || email.contains("@.")) return false + if (email.startsWith(".") || email.endsWith(".")) return false + if (email.startsWith("@") || email.endsWith("@")) return false - fun hasRepeatedSubdomains(email: String): Boolean { val parts = email.split("@") + if (parts.size != 2) return false - if (parts.size == 2) { - val subdomains = parts[1].split(".") - val verifyedSubdomains = HashSet() + val localPart = parts[0] + val domainPart = parts[1] - for (subdomain in subdomains){ - if (!verifyedSubdomains.add(subdomain)) return true - } + if (!hasValidLength(localPart, domainPart)) return false + if (!isValidStructure(localPart, domainPart)) return false + + return true + } + + private fun isValidStructure(localPart: String, domainPart: String): Boolean { + val localRegex = Regex("^[A-Za-z0-9_!#$%&'*+/=?`{|}~^.-]+$") + val domainRegex = Regex("^[A-Za-z0-9.-]+$") + + val domainLabels = domainPart.split(".") + if (domainLabels.last().length < 2 || domainLabels.any { it.startsWith("-") || it.endsWith("-") }) { + return false } - return false + + return localRegex.matches(localPart) && domainRegex.matches(domainPart) } - fun hasLengthBelowMaximum(email: String): Boolean { - val parts = email.split("@") - return !(parts[0].length > 64 || parts[1].length > 255) + private fun hasValidLength(localPart: String, domainPart: String): Boolean { + if (localPart.length > 64) return false + if (domainPart.length > 255) return false + if ((localPart.length + 1 + domainPart.length) > 254) return false + return true } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/shared/valueobject/Email.kt b/review/src/main/kotlin/br/all/domain/shared/valueobject/Email.kt index fa3f91af0..aa332b362 100644 --- a/review/src/main/kotlin/br/all/domain/shared/valueobject/Email.kt +++ b/review/src/main/kotlin/br/all/domain/shared/valueobject/Email.kt @@ -7,7 +7,7 @@ data class Email(val email: String) : ValueObject() { init { val notification = validate() - require(notification.hasNoErrors()) {notification.message()} + require(notification.hasNoErrors()) { notification.message() } } override fun validate(): Notification { @@ -17,45 +17,50 @@ data class Email(val email: String) : ValueObject() { notification.addError("Email must not be empty.") return notification } + if (email.isBlank()) { notification.addError("Email must not be blank.") return notification } + if (!isValidEmailFormat(email)) notification.addError("Wrong Email format.") + return notification } private fun isValidEmailFormat(email: String): Boolean { - if (!isValidEmailAddress(email)) return false - if (!HasLengthBelowMaximum(email)) return false - if (hasRepeatedSubdomains(email)) return false - if (email.contains("..")) return false - if (email.contains("@.")) return false - if (email.contains(".@")) return false - return true - } - - private fun isValidEmailAddress(email: String): Boolean { - val regex = Regex("^[A-Za-z0-9+_.-]+@[a-z.]+$") - return regex.matches(email) - } + if (email.contains("..") || email.contains(".@") || email.contains("@.")) return false + if (email.startsWith(".") || email.endsWith(".")) return false + if (email.startsWith("@") || email.endsWith("@")) return false - fun hasRepeatedSubdomains(email: String): Boolean { val parts = email.split("@") + if (parts.size != 2) return false + + val localPart = parts[0] + val domainPart = parts[1] - if (parts.size == 2) { - val subdomains = parts[1].split(".") - val verifyedSubdomains = HashSet() + if (!hasValidLength(localPart, domainPart)) return false + if (!isValidStructure(localPart, domainPart)) return false - for (subdomain in subdomains){ - if (!verifyedSubdomains.add(subdomain)) return true - } + return true + } + + private fun isValidStructure(localPart: String, domainPart: String): Boolean { + val localRegex = Regex("^[A-Za-z0-9_!#$%&'*+/=?`{|}~^.-]+$") + val domainRegex = Regex("^[A-Za-z0-9.-]+$") + + val domainLabels = domainPart.split(".") + if (domainLabels.last().length < 2 || domainLabels.any { it.startsWith("-") || it.endsWith("-") }) { + return false } - return false + + return localRegex.matches(localPart) && domainRegex.matches(domainPart) } - fun HasLengthBelowMaximum(email: String): Boolean { - val parts = email.split("@") - return !(parts[0].length > 64 || parts[1].length > 255) + private fun hasValidLength(localPart: String, domainPart: String): Boolean { + if (localPart.length > 64) return false + if (domainPart.length > 255) return false + if ((localPart.length + 1 + domainPart.length) > 254) return false + return true } } \ No newline at end of file From 878e84f802373d955c0c1c083f3c901cdf2aa160 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 13:56:30 -0300 Subject: [PATCH 084/153] test(email): modify tests with false premises --- .../br/all/domain/shared/ddd/EmailTest.kt | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt b/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt index 1f3348c04..55959a529 100644 --- a/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt +++ b/review/src/test/kotlin/br/all/domain/shared/ddd/EmailTest.kt @@ -61,19 +61,6 @@ class EmailTest { exception.message?.contains("Wrong Email format")?.let { assertTrue(it) } } - - @Test - fun `should not accept email with two equal TLDs`() { - val exception = assertThrows { Email("email@ifsp.com.com") } - exception.message?.contains("Wrong Email format")?.let { assertTrue(it) } - } - - @Test - fun `should not accept email with two equal subdomains`() { - val exception = assertThrows { Email("email@ifsp.ifsp.com") } - exception.message?.contains("Wrong Email format")?.let { assertTrue(it) } - } - @Test fun `email with incorrect format should include error message`() { val exception = assertThrows { Email("invalid-email-format") } @@ -104,7 +91,7 @@ class EmailTest { @Test fun `invalid email with special characters should throw an exception`() { - val exception = assertThrows { Email("user!name@example.com") } + val exception = assertThrows { Email("user name@example.com") } exception.message?.contains("Wrong Email format")?.let { assertTrue(it) } } @@ -151,7 +138,7 @@ class EmailTest { @Test fun `valid email with domain under maximum length should not throw an exception`() { - assertDoesNotThrow { Email("user@" + "a".repeat(251) + ".com") } + assertDoesNotThrow { Email("user@" + "a".repeat(240) + ".com") } } @Test @@ -159,6 +146,4 @@ class EmailTest { val exception = assertThrows { Email("user@domain@com") } exception.message?.contains("Wrong Email format")?.let { assertTrue(it) } } - - } From e6d69157d052116467affe728c154db6fed4d2f5 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 13:56:43 -0300 Subject: [PATCH 085/153] test(email): remove hardcoded email --- .../user/create/RegisterUserAccountServiceImplTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/account/src/test/kotlin/br/all/application/user/create/RegisterUserAccountServiceImplTest.kt b/account/src/test/kotlin/br/all/application/user/create/RegisterUserAccountServiceImplTest.kt index c5d6795b9..10f7cca27 100644 --- a/account/src/test/kotlin/br/all/application/user/create/RegisterUserAccountServiceImplTest.kt +++ b/account/src/test/kotlin/br/all/application/user/create/RegisterUserAccountServiceImplTest.kt @@ -33,7 +33,7 @@ class RegisterUserAccountServiceImplTest { inner class WhenSuccessfullyRegisteringUser { @Test fun `should register a new user`() { - val request = factory.registerRequest().copy(email = "user@example.com") + val request = factory.registerRequest() every { userAccountRepository.existsByEmail(request.email) } returns false every { userAccountRepository.existsByUsername(request.username) } returns false @@ -53,7 +53,7 @@ class RegisterUserAccountServiceImplTest { inner class WhenFailingToRegisterUser { @Test fun `should not register user with existing email`() { - val request = factory.registerRequest().copy(email = "user@example.com") + val request = factory.registerRequest() every { userAccountRepository.existsByEmail(request.email) } returns true every { userAccountRepository.existsByUsername(request.username) } returns false @@ -68,7 +68,7 @@ class RegisterUserAccountServiceImplTest { @Test fun `should not register user with existing username`() { - val request = factory.registerRequest().copy(email = "user@example.com") + val request = factory.registerRequest() every { userAccountRepository.existsByEmail(request.email) } returns false every { userAccountRepository.existsByUsername(request.username) } returns true From 4f6b43d531ab0663821b1d09a20e91a72c769f6c Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 15:50:28 -0300 Subject: [PATCH 086/153] test(studyController): add number and label question generations in data factory --- .../br/all/study/utils/TestDataFactory.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/web/src/test/kotlin/br/all/study/utils/TestDataFactory.kt b/web/src/test/kotlin/br/all/study/utils/TestDataFactory.kt index e98f932f5..d72a0dc5c 100644 --- a/web/src/test/kotlin/br/all/study/utils/TestDataFactory.kt +++ b/web/src/test/kotlin/br/all/study/utils/TestDataFactory.kt @@ -164,6 +164,27 @@ class TestDataFactory { QuestionContextEnum.ROB ) + fun generateRobQuestionNumberScaleDto( + questionId: UUID, + systematicStudyId: UUID = this.systematicStudyId, + code: String = faker.lorem.words(), + description: String = faker.lorem.words(), + lower: Int = 1, + higher: Int = 5 + ) = + QuestionDocument( + questionId, + systematicStudyId, + code, + description, + "NUMBERED_SCALE", + null, + higher, + lower, + null, + QuestionContextEnum.ROB + ) + fun generateExtractionQuestionTextualDto( questionId: UUID, systematicStudyId: UUID = this.systematicStudyId, @@ -182,4 +203,24 @@ class TestDataFactory { null, QuestionContextEnum.EXTRACTION ) + + fun generateExtractionQuestionPickListDto( + questionId: UUID, + systematicStudyId: UUID = this.systematicStudyId, + code: String = faker.lorem.words(), + description: String = faker.lorem.words(), + options: List = listOf("Option A", "Option B", "Option C") + ) = + QuestionDocument( + questionId, + systematicStudyId, + code, + description, + "PICK_LIST", + null, + null, + null, + options, + QuestionContextEnum.EXTRACTION + ) } \ No newline at end of file From e4ce13eafde5712357e5ccd8c4e5db8ed58300e9 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 15:50:43 -0300 Subject: [PATCH 087/153] test(studyController): add new tests for both batch endpoints --- .../controller/StudyReviewControllerTest.kt | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt index 4735a7e39..7a2233ff9 100644 --- a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt +++ b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt @@ -9,8 +9,12 @@ import br.all.infrastructure.study.StudyReviewIdGeneratorService import br.all.security.service.ApplicationUser import br.all.shared.TestHelperService import br.all.study.utils.TestDataFactory +import org.hamcrest.Matchers.containsString +import org.hamcrest.Matchers.hasItem +import org.hamcrest.Matchers.hasSize import org.junit.jupiter.api.* import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Assertions.assertTrue import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc @@ -71,6 +75,12 @@ class StudyReviewControllerTest( fun answerExtractionQuestion(studyReviewId: Long) = "/api/v1/systematic-study/$systematicStudyId/study-review/${studyReviewId}/extraction-answer" + fun batchAnswerRiskOfBiasQuestion(studyReviewId: Long) = + "/api/v1/systematic-study/$systematicStudyId/study-review/${studyReviewId}/batch-riskOfBias-answers" + + fun batchAnswerExtractionQuestion(studyReviewId: Long) = + "/api/v1/systematic-study/$systematicStudyId/study-review/${studyReviewId}/batch-extraction-answers" + @BeforeEach fun setUp() { repository.deleteAll() @@ -639,6 +649,167 @@ class StudyReviewControllerTest( } } + @Nested + @DisplayName("When batch answering ROB questions in a review") + inner class BatchAnswerRobQuestionsTests( + @Autowired val questionRepository: MongoQuestionRepository + ) { + @Test + @DisplayName("should save valid answers, ignore invalid ones, and return 200 with a detailed report") + fun `should handle partial success correctly`() { + val studyId = idService.next() + val studyReview = factory.reviewDocument(systematicStudyId, studyId) + repository.insert(studyReview) + + val validQId1 = UUID.randomUUID() + val validQId2 = UUID.randomUUID() + val invalidQId = UUID.randomUUID() + + val question1 = factory.generateRobQuestionTextualDto(validQId1, systematicStudyId) + val question2 = factory.generateRobQuestionTextualDto(validQId2, systematicStudyId) + val question3 = factory.generateRobQuestionNumberScaleDto(invalidQId, systematicStudyId) + + questionRepository.insert(question1) + questionRepository.insert(question2) + questionRepository.insert(question3) + + val jsonPayload = """ + { + "answers": [ + { "questionId": "$validQId1", "type": "TEXTUAL", "answer": "First valid answer" }, + { "questionId": "$validQId2", "type": "TEXTUAL", "answer": "Second valid answer" }, + { "questionId": "$invalidQId", "type": "NUMBERED_SCALE", "answer": "This shouldn't be a string" } + ] + } + """.trimIndent() + + mockMvc.perform( + patch(batchAnswerRiskOfBiasQuestion(studyId)) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + .contentType(MediaType.APPLICATION_JSON).content(jsonPayload) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.totalAnswered").value(2)) + .andExpect(jsonPath("$.succeededAnswers", hasSize(2))) + .andExpect(jsonPath("$.succeededAnswers", hasItem(validQId1.toString()))) + .andExpect(jsonPath("$.succeededAnswers", hasItem(validQId2.toString()))) + .andExpect(jsonPath("$.failedAnswers", hasSize(1))) + .andExpect(jsonPath("$.failedAnswers[0].questionId").value(invalidQId.toString())) + .andExpect(jsonPath("$.failedAnswers[0].reason", containsString("not compatible with question type 'NUMBERED_SCALE'"))) + + val updatedReview = repository.findById(StudyReviewId(systematicStudyId, studyId)).get() + + assertEquals(3, updatedReview.qualityAnswers.size) + assertEquals("First valid answer", updatedReview.qualityAnswers[validQId1]) + assertEquals("Second valid answer", updatedReview.qualityAnswers[validQId2]) + assertNull(updatedReview.qualityAnswers[invalidQId]) + } + + @Test + @DisplayName("should return 401 for unauthenticated users") + fun `should not update if user is unauthenticated`() { + testHelperService.testForUnauthenticatedUser(mockMvc, patch(batchAnswerRiskOfBiasQuestion(1L))) + } + + @Test + @DisplayName("should return 403 for unauthorized users") + fun `should not update if user is unauthorized`() { + val jsonPayload = """{ "answers": [] }""" + testHelperService.testForUnauthorizedUser( + mockMvc, + patch(batchAnswerRiskOfBiasQuestion(1L)).content(jsonPayload) + ) + } + } + + @Nested + @DisplayName("When batch answering Extraction questions in a review") + inner class BatchAnswerExtractionQuestionsTests( + @Autowired val questionRepository: MongoQuestionRepository + ) { + @Test + @DisplayName("should save all valid answers and return 200 with no failures") + fun `should handle full success correctly`() { + val studyId = idService.next() + val studyReview = factory.reviewDocument(systematicStudyId, studyId) + repository.insert(studyReview) + + val textQId = UUID.randomUUID() + val pickListQId = UUID.randomUUID() + + val question1 = factory.generateExtractionQuestionTextualDto(textQId, systematicStudyId = systematicStudyId) + val question2 = factory.generateExtractionQuestionPickListDto(pickListQId, systematicStudyId = systematicStudyId) + + questionRepository.insert(question1) + questionRepository.insert(question2) + + val jsonPayload = """ + { + "answers": [ + { "questionId": "$textQId", "type": "TEXTUAL", "answer": "Another valid answer" }, + { "questionId": "$pickListQId", "type": "PICK_LIST", "answer": "Option A" } + ] + } + """.trimIndent() + + mockMvc.perform( + patch(batchAnswerExtractionQuestion(studyId)) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + .contentType(MediaType.APPLICATION_JSON).content(jsonPayload) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.totalAnswered").value(2)) + .andExpect(jsonPath("$.succeededAnswers", hasSize(2))) + .andExpect(jsonPath("$.failedAnswers", hasSize(0))) + + val updatedReview = repository.findById(StudyReviewId(systematicStudyId, studyId)).get() + assertEquals(3, updatedReview.formAnswers.size) + assertEquals("Another valid answer", updatedReview.formAnswers[textQId]) + assertEquals("Option A", updatedReview.formAnswers[pickListQId]) + } + + @Test + @DisplayName("should not save answers if the question context is wrong") + fun `should fail on context mismatch`() { + val studyId = idService.next() + repository.insert(factory.reviewDocument(systematicStudyId, studyId)) + + val extractionQId = UUID.randomUUID() + questionRepository.insert(factory.generateExtractionQuestionTextualDto(extractionQId, systematicStudyId = systematicStudyId)) + + val jsonPayload = """ + { "answers": [{ "questionId": "$extractionQId", "type": "TEXTUAL", "answer": "some answer" }] } + """ + + mockMvc.perform( + patch(batchAnswerRiskOfBiasQuestion(studyId)) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + .contentType(MediaType.APPLICATION_JSON).content(jsonPayload) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.totalAnswered").value(0)) + .andExpect(jsonPath("$.failedAnswers", hasSize(1))) + .andExpect(jsonPath("$.failedAnswers[0].questionId").value(extractionQId.toString())) + .andExpect(jsonPath("$.failedAnswers[0].reason", containsString("Should answer question with the context: ROB"))) + } + + @Test + @DisplayName("should return 401 for unauthenticated users") + fun `should not update if user is unauthenticated`() { + testHelperService.testForUnauthenticatedUser(mockMvc, patch(batchAnswerExtractionQuestion(1L))) + } + + @Test + @DisplayName("should return 403 for unauthorized users") + fun `should not update if user is unauthorized`() { + val jsonPayload = """{ "answers": [] }""" + testHelperService.testForUnauthorizedUser( + mockMvc, + patch(batchAnswerExtractionQuestion(1L)).content(jsonPayload) + ) + } + } + @Nested @DisplayName("When marking a study review as duplicated") inner class MarkingAsDuplicatedTests { From 976408b449b35f7a370122a9c80f7ef42ee7b6ec Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 26 Jun 2025 16:03:14 -0300 Subject: [PATCH 088/153] test(batchAnswer): WIP add service test setup --- .../BatchAnswerQuestionServiceImplTest.kt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt diff --git a/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt new file mode 100644 index 000000000..a8e12f75d --- /dev/null +++ b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt @@ -0,0 +1,65 @@ +package br.all.application.study.update + +import br.all.application.question.repository.QuestionRepository +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.study.repository.StudyReviewRepository +import br.all.application.study.update.implementation.BatchAnswerQuestionServiceImpl +import br.all.application.study.update.interfaces.BatchAnswerQuestionPresenter +import br.all.application.study.util.TestDataFactory +import br.all.application.user.CredentialsService +import br.all.application.util.PreconditionCheckerMockingNew +import io.mockk.impl.annotations.MockK +import io.mockk.junit5.MockKExtension +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID + +@Tag("UnitTest") +@Tag("ServiceTest") +@ExtendWith(MockKExtension::class) +class BatchAnswerQuestionServiceImplTest { + + @MockK(relaxed = true) + private lateinit var studyReviewRepository: StudyReviewRepository + + @MockK + private lateinit var systematicStudyRepository: SystematicStudyRepository + + @MockK + private lateinit var questionRepository: QuestionRepository + + @MockK + private lateinit var credentialsService: CredentialsService + + @MockK(relaxed = true) + private lateinit var presenter: BatchAnswerQuestionPresenter + + private lateinit var sut: BatchAnswerQuestionServiceImpl + private lateinit var factory: TestDataFactory + private lateinit var preconditionCheckerMocking: PreconditionCheckerMockingNew + private lateinit var questionId: UUID + + @BeforeEach + fun setUp() { + factory = TestDataFactory() + preconditionCheckerMocking = PreconditionCheckerMockingNew( + presenter, + credentialsService, + systematicStudyRepository, + factory.researcherId, + factory.systematicStudyId + ) + sut = BatchAnswerQuestionServiceImpl( + studyReviewRepository, + questionRepository, + systematicStudyRepository, + credentialsService + ) + questionId = UUID.randomUUID() + } + + + + +} \ No newline at end of file From 5b09b436f829d11b6adf21a9bec5c6e2c3f455b1 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Sat, 28 Jun 2025 17:05:41 -0300 Subject: [PATCH 089/153] test(batchAnswer): add request model generation in data factory --- .../application/study/util/TestDataFactory.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/review/src/test/kotlin/br/all/application/study/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/study/util/TestDataFactory.kt index ad2554d20..63640d153 100644 --- a/review/src/test/kotlin/br/all/application/study/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/study/util/TestDataFactory.kt @@ -220,6 +220,27 @@ class TestDataFactory { QuestionContextEnum.valueOf(questionContext), ) + fun batchAnswerRequest( + answers: List, + researcherId: UUID = this.researcherId, + systematicStudyId: UUID = this.systematicStudyId, + studyReviewId: Long = this.studyReviewId, + ) = BatchAnswerQuestionService.RequestModel( + userId = researcherId, + systematicStudyId = systematicStudyId, + studyReviewId = studyReviewId, + answers = answers + ) + + fun answerDetail( + questionId: UUID, + type: String, + answer: Any, + ) = BatchAnswerQuestionService.RequestModel.AnswerDetail( + questionId = questionId, + type = type, + answer = answer + ) operator fun component1() = researcherId operator fun component2() = studyReviewId From 3a0ad4052d1a7d4aa96a8217912a224accdaed00 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Sat, 28 Jun 2025 17:06:04 -0300 Subject: [PATCH 090/153] test(batchAnswer): add tests for batch answer service impl --- .../BatchAnswerQuestionServiceImplTest.kt | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt index a8e12f75d..829b8f8b1 100644 --- a/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt @@ -4,16 +4,24 @@ import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository import br.all.application.study.update.implementation.BatchAnswerQuestionServiceImpl +import br.all.application.study.update.interfaces.AnswerQuestionService import br.all.application.study.update.interfaces.BatchAnswerQuestionPresenter import br.all.application.study.util.TestDataFactory import br.all.application.user.CredentialsService import br.all.application.util.PreconditionCheckerMockingNew +import io.mockk.every import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension +import io.mockk.verify import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.extension.ExtendWith import java.util.UUID +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertTrue @Tag("UnitTest") @Tag("ServiceTest") @@ -59,7 +67,174 @@ class BatchAnswerQuestionServiceImplTest { questionId = UUID.randomUUID() } + @Nested + @DisplayName("When successfully answering questions") + inner class WhenSuccessfullyAnsweringQuestions { + @Test + fun `should successfully answer multiple questions of different types`() { + val reviewDto = factory.generateDto() + val context = "EXTRACTION" + val textualQId = UUID.randomUUID() + val textualQDto = factory.generateQuestionTextualDto(textualQId, factory.systematicStudyId, questionContext = context) + val textualAnswer = factory.answerDetail(questionId = textualQId, type = "TEXTUAL", answer = "Valid textual answer") + val numberedQId = UUID.randomUUID() + val numberedQDto = factory.generateQuestionNumberedScaleDto(numberedQId, factory.systematicStudyId, questionContext = context, higher = 5, lower = 1) + val numberedAnswer = factory.answerDetail(questionId = numberedQId, type = "NUMBERED_SCALE", answer = 5) + + val pickListQId = UUID.randomUUID() + val pickListQDto = factory.generateQuestionPickListDto(pickListQId, factory.systematicStudyId, options = listOf("A", "B"), questionContext = context) + val pickListAnswer = factory.answerDetail(questionId = pickListQId, type = "PICK_LIST", answer = "A") + + val request = factory.batchAnswerRequest(listOf(textualAnswer, numberedAnswer, pickListAnswer)) + + preconditionCheckerMocking.makeEverythingWork() + + every { studyReviewRepository.findById(request.systematicStudyId, request.studyReviewId) } returns reviewDto + every { questionRepository.findById(request.systematicStudyId, textualQId) } returns textualQDto + every { questionRepository.findById(request.systematicStudyId, numberedQId) } returns numberedQDto + every { questionRepository.findById(request.systematicStudyId, pickListQId) } returns pickListQDto + + sut.batchAnswerQuestion(presenter, request, context) + + verify(exactly = 1) { studyReviewRepository.saveOrUpdate(any()) } + verify(exactly = 1) { + presenter.prepareSuccessView(withArg { response -> + assertEquals(3, response.succeededAnswers.size) + assertTrue(response.failedAnswers.isEmpty()) + assertEquals(3, response.totalAnswered) + assertTrue(response.succeededAnswers.containsAll(listOf(textualQId, numberedQId, pickListQId))) + }) + } + } + + @Test + fun `should handle a mix of successful and failed answers`() { + val reviewDto = factory.generateDto() + val context = "ROB" + + val successQId = UUID.randomUUID() + val successQDto = factory.generateQuestionTextualDto(successQId, factory.systematicStudyId, questionContext = context) + val successAnswer = factory.answerDetail(questionId = successQId, type = "TEXTUAL", answer = "This will work") + + val notFoundQId = UUID.randomUUID() + val notFoundAnswer = factory.answerDetail(questionId = notFoundQId, type = "TEXTUAL", answer = "This will fail") + + val wrongContextQId = UUID.randomUUID() + val wrongContextQDto = factory.generateQuestionTextualDto(wrongContextQId, factory.systematicStudyId, questionContext = "EXTRACTION") + val wrongContextAnswer = factory.answerDetail(questionId = wrongContextQId, type = "TEXTUAL", answer = "Wrong context") + + val request = factory.batchAnswerRequest(listOf(successAnswer, notFoundAnswer, wrongContextAnswer)) + + preconditionCheckerMocking.makeEverythingWork() + + every { studyReviewRepository.findById(request.systematicStudyId, request.studyReviewId) } returns reviewDto + every { questionRepository.findById(request.systematicStudyId, successQId) } returns successQDto + every { questionRepository.findById(request.systematicStudyId, notFoundQId) } returns null + every { questionRepository.findById(request.systematicStudyId, wrongContextQId) } returns wrongContextQDto + + sut.batchAnswerQuestion(presenter, request, context) + + verify(exactly = 1) { studyReviewRepository.saveOrUpdate(any()) } + verify(exactly = 1) { + presenter.prepareSuccessView(withArg { response -> + assertEquals(1, response.succeededAnswers.size) + assertEquals(2, response.failedAnswers.size) + assertEquals(1, response.totalAnswered) + assertTrue(response.succeededAnswers.contains(successQId)) + assertTrue(response.failedAnswers.any { it.questionId == notFoundQId }) + assertTrue(response.failedAnswers.any { it.questionId == wrongContextQId }) + }) + } + } + } + + @Nested + @DisplayName("When failing to answer questions") + inner class WhenFailingToAnswerQuestions { + @Test + fun `should create a failed answer entry for a question with conflicting types`() { + val reviewDto = factory.generateDto() + val context = "ROB" + val questionId = UUID.randomUUID() + val questionDto = factory.generateQuestionTextualDto(questionId, factory.systematicStudyId, questionContext = context) + + val answerDetail = factory.answerDetail(questionId, "PICK_LIST", "Some answer") + val request = factory.batchAnswerRequest(listOf(answerDetail)) + + preconditionCheckerMocking.makeEverythingWork() + every { studyReviewRepository.findById(any(), any()) } returns reviewDto + every { questionRepository.findById(any(), questionId) } returns questionDto + + sut.batchAnswerQuestion(presenter, request, context) + + verify(exactly = 1) { + presenter.prepareSuccessView(withArg { response -> + assertTrue(response.succeededAnswers.isEmpty()) + assertEquals(1, response.failedAnswers.size) + assertEquals(questionId, response.failedAnswers.first().questionId) + assertTrue("Type mismatch" in response.failedAnswers.first().reason) + }) + } + } + + @Test + fun `should create a failed answer entry when answer value type is incompatible`() { + val reviewDto = factory.generateDto() + val context = "EXTRACTION" + val questionId = UUID.randomUUID() + val questionDto = factory.generateQuestionTextualDto(questionId, factory.systematicStudyId, questionContext = context) + + val answerDetail = factory.answerDetail(questionId, "TEXTUAL", 12345) + val request = factory.batchAnswerRequest(listOf(answerDetail)) + + preconditionCheckerMocking.makeEverythingWork() + + every { studyReviewRepository.findById(any(), any()) } returns reviewDto + every { questionRepository.findById(any(), questionId) } returns questionDto + + sut.batchAnswerQuestion(presenter, request, context) + + verify(exactly = 1) { + presenter.prepareSuccessView(withArg { response -> + assertTrue(response.succeededAnswers.isEmpty()) + assertEquals(1, response.failedAnswers.size) + assertEquals(questionId, response.failedAnswers.first().questionId) + assertTrue("is not compatible with question type" in response.failedAnswers.first().reason) + }) + } + } + + @Test + fun `should create a failed answer entry for unsupported labeled scale answer type`() { + val reviewDto = factory.generateDto() + val context = "ROB" + val questionId = UUID.randomUUID() + val labelDto = AnswerQuestionService.LabelDto( + "LabelTest", + 1 + ) + val questionDto = factory.generateQuestionLabeledScaleDto(questionId, factory.systematicStudyId, questionContext = context, labelDto = labelDto) + + val answerDetail = factory.answerDetail(questionId, "LABELED_SCALE", "invalid answer format") + val request = factory.batchAnswerRequest(listOf(answerDetail)) + + preconditionCheckerMocking.makeEverythingWork() + every { studyReviewRepository.findById(any(), any()) } returns reviewDto + every { questionRepository.findById(any(), questionId) } returns questionDto + + sut.batchAnswerQuestion(presenter, request, context) + + verify(exactly = 1) { + presenter.prepareSuccessView(withArg { response -> + assertTrue(response.succeededAnswers.isEmpty()) + assertEquals(1, response.failedAnswers.size) + assertEquals(questionId, response.failedAnswers.first().questionId) + assertTrue("Unsupported answer type for 'LABELED_SCALE'" in response.failedAnswers.first().reason) + }) + } + } + } } \ No newline at end of file From 719da3d4bd0bf6f4e1c7d7f645baa9be2f92ca5b Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:02:47 -0300 Subject: [PATCH 091/153] chore: add picoc word to the dictionary --- .idea/dictionaries/project.xml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .idea/dictionaries/project.xml diff --git a/.idea/dictionaries/project.xml b/.idea/dictionaries/project.xml new file mode 100644 index 000000000..a7265e4c8 --- /dev/null +++ b/.idea/dictionaries/project.xml @@ -0,0 +1,7 @@ + + + + picoc + + + \ No newline at end of file From c671e08eb897c8e913c92a32a7e4fe15eb77c8ad Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:03:03 -0300 Subject: [PATCH 092/153] feat(protocolStage): add protocol stage presenter --- .../application/protocol/find/GetProtocolStagePresenter.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStagePresenter.kt diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStagePresenter.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStagePresenter.kt new file mode 100644 index 000000000..8ba8c5d9b --- /dev/null +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStagePresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.protocol.find + +import br.all.application.shared.presenter.GenericPresenter +import br.all.application.protocol.find.GetProtocolStageService.ResponseModel + +interface GetProtocolStagePresenter : GenericPresenter \ No newline at end of file From 2fcc5d94a36ecac2df36f1e89e849e3faf34ec8a Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:03:09 -0300 Subject: [PATCH 093/153] feat(protocolStage): add protocol stage service --- .../protocol/find/GetProtocolStageService.kt | 30 ++++++ .../find/GetProtocolStageServiceImpl.kt | 98 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt create mode 100644 review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt new file mode 100644 index 000000000..b4a9b2ccf --- /dev/null +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt @@ -0,0 +1,30 @@ +package br.all.application.protocol.find + +import java.util.UUID + +interface GetProtocolStageService { + fun getStage(presenter: GetProtocolStagePresenter, request: RequestModel) + + data class RequestModel( + val userId: UUID, + val systematicStudyId: UUID + ) + + data class ResponseModel( + val userId: UUID, + val systematicStudyId: UUID, + val stage: ProtocolStage + ) + + enum class ProtocolStage { + PROTOCOL_PART_I, + PICOC, + PROTOCOL_PART_II, + PROTOCOL_PART_III, + IDENTIFICATION, + SELECTION, + EXTRACTION, + GRAPHICS, + FINALIZATION + } +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt new file mode 100644 index 000000000..c242cce42 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -0,0 +1,98 @@ +package br.all.application.protocol.find + +import br.all.application.protocol.repository.ProtocolRepository +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.user.CredentialsService +import br.all.application.protocol.find.GetProtocolStageService.RequestModel +import br.all.application.protocol.find.GetProtocolStageService.ResponseModel +import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage +import br.all.application.protocol.repository.ProtocolDto +import br.all.application.review.repository.fromDto +import br.all.application.shared.exceptions.EntityNotFoundException +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.study.repository.StudyReviewRepository +import br.all.domain.model.review.SystematicStudy +import org.springframework.stereotype.Service + +@Service +class GetProtocolStageServiceImpl( + private val protocolRepository: ProtocolRepository, + private val systematicStudyRepository: SystematicStudyRepository, + private val studyReviewRepository: StudyReviewRepository, + private val credentialsService: CredentialsService +) : GetProtocolStageService { + override fun getStage(presenter: GetProtocolStagePresenter, request: RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + if (presenter.isDone()) return + + val protocolDto = protocolRepository.findById(request.systematicStudyId) + if (protocolDto == null) { + val message = "Protocol not found for systematic study ${request.systematicStudyId}" + presenter.prepareFailView(EntityNotFoundException(message)) + return + } + + val allStudies = studyReviewRepository.findAllFromReview(request.systematicStudyId) + + val totalStudiesCount = allStudies.size + val includedStudiesCount = allStudies.count { it.selectionStatus == "INCLUDED" } + val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } + + val stage = evaluateStage(protocolDto, totalStudiesCount, includedStudiesCount, extractedStudiesCount) + + presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) + } + + + private fun evaluateStage(dto: ProtocolDto, totalStudiesCount: Int, includedStudiesCount: Int, extractedStudiesCount: Int) : ProtocolStage { + if (dto.goal.isNullOrBlank() && dto.justification.isNullOrBlank()) { + return ProtocolStage.PROTOCOL_PART_I + } + + val picoc = dto.picoc + if (picoc == null || (picoc.population.isNullOrBlank() && picoc.intervention.isNullOrBlank() && + picoc.control.isNullOrBlank() && picoc.outcome.isNullOrBlank() && picoc.context.isNullOrBlank())) { + return ProtocolStage.PICOC + } + + if (dto.studiesLanguages.isEmpty() && dto.eligibilityCriteria.isEmpty() && + dto.informationSources.isEmpty() && dto.keywords.isEmpty() && + dto.sourcesSelectionCriteria.isNullOrBlank() && dto.searchMethod.isNullOrBlank() && + dto.selectionProcess.isNullOrBlank()) { + return ProtocolStage.PROTOCOL_PART_II + } + + val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } + val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } + + if (dto.extractionQuestions.isEmpty() || dto.robQuestions.isEmpty() || + !hasInclusionCriteria || !hasExclusionCriteria || + dto.informationSources.isEmpty() || + !dto.researchQuestions.isEmpty() || !dto.analysisAndSynthesisProcess.isNullOrBlank()) { + return ProtocolStage.PROTOCOL_PART_III + } + + if (totalStudiesCount == 0) { + return ProtocolStage.IDENTIFICATION + } + + if (includedStudiesCount == 0) { + return ProtocolStage.SELECTION + } + + if (extractedStudiesCount == 0) { + return ProtocolStage.EXTRACTION + } + + // This stage is reached when extraction is complete, but finalization has not yet begun. + // As Finalization criteria are not yet defined, this is the default final step. + return ProtocolStage.GRAPHICS + + // Finalization would be returned here once its criteria are defined. + } +} \ No newline at end of file From cb7a7bda38b88843ea7d620108e919e96113c429 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:03:22 -0300 Subject: [PATCH 094/153] feat(protocolStage): add protocol stage restful presenter --- .../RestfulGetProtocolStagePresenter.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt diff --git a/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt b/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt new file mode 100644 index 000000000..f65b36851 --- /dev/null +++ b/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt @@ -0,0 +1,32 @@ +package br.all.protocol.presenter + +import br.all.application.protocol.find.GetProtocolStagePresenter +import br.all.application.protocol.find.GetProtocolStageService.ResponseModel +import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage +import br.all.shared.error.createErrorResponseFrom +import br.all.utils.LinksFactory +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.UUID + +class RestfulGetProtocolStagePresenter( + private val linksFactory: LinksFactory +) : GetProtocolStagePresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: ResponseModel) { + val viewModel = ViewModel(response.userId, response.systematicStudyId, response.stage) + responseEntity = ResponseEntity.status(HttpStatus.OK).body(viewModel) + } + + override fun prepareFailView(throwable: Throwable) = run { responseEntity = createErrorResponseFrom(throwable) } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val researcherId: UUID, + val systematicStudyId: UUID, + val currentStage: ProtocolStage, + ) : RepresentationModel() +} \ No newline at end of file From 93e537a81aef8c3a5dbd36d0d72ddb3357211c40 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:03:38 -0300 Subject: [PATCH 095/153] feat(protocolStage): add protocol stage endpoint to protocol controller --- .../protocol/controller/ProtocolController.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/web/src/main/kotlin/br/all/protocol/controller/ProtocolController.kt b/web/src/main/kotlin/br/all/protocol/controller/ProtocolController.kt index 4bf028a1e..8ef4aef3a 100644 --- a/web/src/main/kotlin/br/all/protocol/controller/ProtocolController.kt +++ b/web/src/main/kotlin/br/all/protocol/controller/ProtocolController.kt @@ -1,8 +1,10 @@ package br.all.protocol.controller import br.all.application.protocol.find.FindProtocolService +import br.all.application.protocol.find.GetProtocolStageService import br.all.application.protocol.update.UpdateProtocolService import br.all.protocol.presenter.RestfulFindProtocolPresenter +import br.all.protocol.presenter.RestfulGetProtocolStagePresenter import br.all.protocol.presenter.RestfulUpdateProtocolPresenter import br.all.protocol.requests.PutRequest import br.all.security.service.AuthenticationInfoService @@ -17,12 +19,14 @@ import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* import java.util.* import br.all.application.protocol.find.FindProtocolService.RequestModel as FindOneRequestModel +import br.all.application.protocol.find.GetProtocolStageService.RequestModel as FindStageRequestModel @RestController @RequestMapping("/systematic-study/{systematicStudyId}/protocol") class ProtocolController( private val findProtocolService: FindProtocolService, private val updateProtocolService: UpdateProtocolService, + private val getProtocolStageService: GetProtocolStageService, private val authenticationInfoService: AuthenticationInfoService, private val linksFactory: LinksFactory ) { @@ -86,4 +90,38 @@ class ProtocolController( return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) } + @GetMapping("/stage") + @Operation(summary = "Get the current stage of the systematic review protocol") + @ApiResponses(value = [ + ApiResponse(responseCode = "200", description = "Success getting the protocol stage", + content = [Content( + mediaType = "application/json", + schema = Schema(implementation = GetProtocolStageService.ResponseModel::class) + )]), + ApiResponse( + responseCode = "401", + description = "Fail getting the protocol stage - unauthenticated collaborator", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "403", + description = "Fail getting the protocol stage - unauthorized collaborator", + content = [Content(schema = Schema(hidden = true))] + ), + ApiResponse( + responseCode = "404", + description = "Fail getting the protocol stage - nonexistent protocol or systematic study", + content = [Content(schema = Schema(hidden = true))] + ), + ]) + fun getStage( + @PathVariable systematicStudyId: UUID + ) : ResponseEntity<*> { + val presenter = RestfulGetProtocolStagePresenter(linksFactory) + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = FindStageRequestModel(userId, systematicStudyId) + + getProtocolStageService.getStage(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } } From df81378314bc45875b25c43e98fc9cd7f3eaa5dc Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Mon, 30 Jun 2025 15:16:01 -0300 Subject: [PATCH 096/153] docs(protocolStage): fix swagger response model for protocol stage endpoint --- .../all/application/protocol/find/GetProtocolStageService.kt | 4 +++- .../protocol/presenter/RestfulGetProtocolStagePresenter.kt | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt index b4a9b2ccf..31ba40773 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageService.kt @@ -1,5 +1,6 @@ package br.all.application.protocol.find +import io.swagger.v3.oas.annotations.media.Schema import java.util.UUID interface GetProtocolStageService { @@ -10,10 +11,11 @@ interface GetProtocolStageService { val systematicStudyId: UUID ) + @Schema(name = "GetProtocolStageServiceResponseModel", description = "Response model for Get Protocol Stage Service") data class ResponseModel( val userId: UUID, val systematicStudyId: UUID, - val stage: ProtocolStage + val currentStage: ProtocolStage ) enum class ProtocolStage { diff --git a/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt b/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt index f65b36851..760cb5f3f 100644 --- a/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt +++ b/web/src/main/kotlin/br/all/protocol/presenter/RestfulGetProtocolStagePresenter.kt @@ -16,7 +16,7 @@ class RestfulGetProtocolStagePresenter( var responseEntity: ResponseEntity<*>? = null override fun prepareSuccessView(response: ResponseModel) { - val viewModel = ViewModel(response.userId, response.systematicStudyId, response.stage) + val viewModel = ViewModel(response.userId, response.systematicStudyId, response.currentStage) responseEntity = ResponseEntity.status(HttpStatus.OK).body(viewModel) } @@ -24,7 +24,7 @@ class RestfulGetProtocolStagePresenter( override fun isDone() = responseEntity != null - private data class ViewModel( + data class ViewModel( val researcherId: UUID, val systematicStudyId: UUID, val currentStage: ProtocolStage, From 0eb6c2082d3d868e6db77824f9ffe689f28df201 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Tue, 1 Jul 2025 14:31:52 -0300 Subject: [PATCH 097/153] test(protocolStage): add test setup and first test --- .../find/GetProtocolStageServiceImplTest.kt | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt new file mode 100644 index 000000000..02e81308b --- /dev/null +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -0,0 +1,104 @@ +package br.all.application.protocol.find + +import br.all.application.protocol.repository.ProtocolRepository +import br.all.application.protocol.util.TestDataFactory +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.study.repository.StudyReviewRepository +import br.all.application.user.CredentialsService +import br.all.application.util.PreconditionCheckerMockingNew +import io.mockk.every +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.junit5.MockKExtension +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID +import kotlin.test.Test +import br.all.application.protocol.find.GetProtocolStageService.RequestModel +import br.all.application.protocol.find.GetProtocolStageService.ResponseModel +import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage +import io.mockk.verify + +@Tag("UnitTest") +@Tag("ServiceTest") +@ExtendWith(MockKExtension::class) +class GetProtocolStageServiceImplTest { + + @MockK(relaxUnitFun = true) + private lateinit var protocolRepository: ProtocolRepository + + @MockK(relaxUnitFun = true) + private lateinit var systematicStudyRepository: SystematicStudyRepository + + @MockK(relaxUnitFun = true) + private lateinit var studyReviewRepository: StudyReviewRepository + + @MockK + private lateinit var credentialsService: CredentialsService + + @MockK(relaxUnitFun = true) + private lateinit var presenter: GetProtocolStagePresenter + + @InjectMockKs + private lateinit var sut: GetProtocolStageServiceImpl + + private lateinit var precondition: PreconditionCheckerMockingNew + private lateinit var factory: TestDataFactory + + private lateinit var researcherId: UUID + private lateinit var systematicStudyId: UUID + + @BeforeEach + fun setup() { + factory = TestDataFactory() + + researcherId = factory.researcher + systematicStudyId = factory.systematicStudy + + precondition = PreconditionCheckerMockingNew( + presenter, + credentialsService, + systematicStudyRepository, + researcherId, + systematicStudyId + ) + + precondition.makeEverythingWork() + } + + @Nested + @DisplayName("When successfully getting protocol's current stage") + inner class SuccessfullyGettingProtocolStage { + @Test + fun `should return protocol's first stage`() { + val protocolDto = factory.protocolDto( + systematicStudy = systematicStudyId, + goal = null, + justification = null + ) + + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + + val request = RequestModel( + userId = researcherId, + systematicStudyId = systematicStudyId + ) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel( + userId = researcherId, + systematicStudyId = systematicStudyId, + currentStage = ProtocolStage.PROTOCOL_PART_I + ) + + verify(exactly = 1) { + presenter.prepareSuccessView(expectedResponse) + } + } + } +} \ No newline at end of file From 4eded51c5cca37be662293da47f9e3dcc2ca3737 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 13:17:41 -0300 Subject: [PATCH 098/153] fix(protocolStage): change protocol part iii condition to properly catch the stage --- .../protocol/find/GetProtocolStageServiceImpl.kt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index c242cce42..f95e9c40d 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -70,10 +70,16 @@ class GetProtocolStageServiceImpl( val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } - if (dto.extractionQuestions.isEmpty() || dto.robQuestions.isEmpty() || - !hasInclusionCriteria || !hasExclusionCriteria || - dto.informationSources.isEmpty() || - !dto.researchQuestions.isEmpty() || !dto.analysisAndSynthesisProcess.isNullOrBlank()) { + val isSetupComplete = dto.extractionQuestions.isNotEmpty() && + dto.robQuestions.isNotEmpty() && + hasInclusionCriteria && + hasExclusionCriteria && + dto.informationSources.isNotEmpty() + + val areFinalFieldsFilled = dto.researchQuestions.isNotEmpty() && + !dto.analysisAndSynthesisProcess.isNullOrBlank() + + if (!isSetupComplete || !areFinalFieldsFilled) { return ProtocolStage.PROTOCOL_PART_III } From 5880f10d02b6f928210fade8d0d72abc5502f9ba Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 13:18:10 -0300 Subject: [PATCH 099/153] test(protocolStage): add all missing happy path tests --- .../find/GetProtocolStageServiceImplTest.kt | 210 ++++++++++++++++-- 1 file changed, 192 insertions(+), 18 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt index 02e81308b..3f5ee9566 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -1,7 +1,8 @@ package br.all.application.protocol.find import br.all.application.protocol.repository.ProtocolRepository -import br.all.application.protocol.util.TestDataFactory +import br.all.application.protocol.util.TestDataFactory as ProtocolFactory +import br.all.application.study.util.TestDataFactory as StudyReviewFactory import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService @@ -20,6 +21,8 @@ import kotlin.test.Test import br.all.application.protocol.find.GetProtocolStageService.RequestModel import br.all.application.protocol.find.GetProtocolStageService.ResponseModel import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage +import br.all.application.protocol.repository.CriterionDto +import br.all.application.protocol.repository.PicocDto import io.mockk.verify @Tag("UnitTest") @@ -46,17 +49,19 @@ class GetProtocolStageServiceImplTest { private lateinit var sut: GetProtocolStageServiceImpl private lateinit var precondition: PreconditionCheckerMockingNew - private lateinit var factory: TestDataFactory + private lateinit var protocolFactory: ProtocolFactory + private lateinit var studyReviewFactory: StudyReviewFactory private lateinit var researcherId: UUID private lateinit var systematicStudyId: UUID @BeforeEach fun setup() { - factory = TestDataFactory() + protocolFactory = ProtocolFactory() + studyReviewFactory = StudyReviewFactory() - researcherId = factory.researcher - systematicStudyId = factory.systematicStudy + researcherId = protocolFactory.researcher + systematicStudyId = protocolFactory.systematicStudy precondition = PreconditionCheckerMockingNew( presenter, @@ -73,32 +78,201 @@ class GetProtocolStageServiceImplTest { @DisplayName("When successfully getting protocol's current stage") inner class SuccessfullyGettingProtocolStage { @Test - fun `should return protocol's first stage`() { - val protocolDto = factory.protocolDto( + fun `should return PROTOCOL_PART_I stage when goal and justification are empty`() { + val protocolDto = protocolFactory.protocolDto( systematicStudy = systematicStudyId, goal = null, justification = null ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_I) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return PICOC stage when it is not filled`() { + val protocolDto = protocolFactory.protocolDto( + systematicStudy = systematicStudyId, + goal = "A goal", + justification = "A justification", + picoc = null + ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PICOC) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return PROTOCOL_PART_II stage when its fields are empty`() { + val protocolDto = protocolFactory.protocolDto( + systematicStudy = systematicStudyId, + goal = "A goal", + justification = "A justification", + picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), + studiesLanguages = emptySet(), + eligibilityCriteria = emptySet(), + informationSources = emptySet(), + keywords = emptySet() + ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_II) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return PROTOCOL_PART_III stage when its conditions are not met`() { + val protocolDto = protocolFactory.protocolDto( + systematicStudy = systematicStudyId, + goal = "A goal", + justification = "A justification", + picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), + keywords = setOf("test"), + extractionQuestions = emptySet() + ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.PROTOCOL_PART_III) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return IDENTIFICATION stage when no studies have been submitted`() { + val protocolDto = createFullProtocolDto() every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() - val request = RequestModel( - userId = researcherId, - systematicStudyId = systematicStudyId + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.IDENTIFICATION) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return SELECTION stage when studies exist but none are included`() { + val protocolDto = createFullProtocolDto() + + val studies = listOf( + createFullStudyReviewDto(selectionStatus = "REJECTED", extractionStatus = "PENDING") ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + + val request = RequestModel(researcherId, systematicStudyId) + sut.getStage(presenter, request) - val expectedResponse = ResponseModel( - userId = researcherId, - systematicStudyId = systematicStudyId, - currentStage = ProtocolStage.PROTOCOL_PART_I + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.SELECTION) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return EXTRACTION stage when studies are included but none are extracted`() { + val protocolDto = createFullProtocolDto() + + val studies = listOf( + createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "PENDING") ) - verify(exactly = 1) { - presenter.prepareSuccessView(expectedResponse) - } + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.EXTRACTION) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } + } + + @Test + fun `should return GRAPHICS stage when studies have been extracted`() { + val protocolDto = createFullProtocolDto() + + val studies = listOf( + createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "INCLUDED") + ) + + every { protocolRepository.findById(systematicStudyId) } returns protocolDto + every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + + val request = RequestModel(researcherId, systematicStudyId) + + sut.getStage(presenter, request) + + val expectedResponse = ResponseModel(researcherId, systematicStudyId, ProtocolStage.GRAPHICS) + verify(exactly = 1) { presenter.prepareSuccessView(expectedResponse) } } } -} \ No newline at end of file + + private fun createFullProtocolDto() = protocolFactory.protocolDto( + systematicStudy = systematicStudyId, + goal = "A goal", + justification = "A justification", + picoc = PicocDto(population = "P", intervention = "I", control = "C", outcome = "O", context = "C"), + studiesLanguages = setOf("English"), + eligibilityCriteria = setOf( + CriterionDto("test description", "INCLUSION"), + CriterionDto("test description", "EXCLUSION") + ), + informationSources = setOf("IEEE"), + keywords = setOf("test"), + sourcesSelectionCriteria = "criteria", + searchMethod = "method", + selectionProcess = "process", + extractionQuestions = setOf(UUID.randomUUID()), + robQuestions = setOf(UUID.randomUUID()), + researchQuestions = setOf("RQ1?"), + analysisAndSynthesisProcess = "process" + ) + + private fun createFullStudyReviewDto(selectionStatus: String, extractionStatus: String) = studyReviewFactory.generateDto( + studyReviewId = 1L, + systematicStudyId = systematicStudyId, + searchSessionId = UUID.randomUUID(), + type = "type", + title = "title", + year = 2025, + authors = "authors", + venue = "venue", + abstract = "abstract", + keywords = emptySet(), + references = emptyList(), + doi = "doi", + sources = emptySet(), + criteria = emptySet(), + formAnswers = emptyMap(), + robAnswers = emptyMap(), + comments = "comments", + readingPriority = "HIGH", + extractionStatus = extractionStatus, + selectionStatus = selectionStatus, + score = 10 + ) +} From fe3edb3a43b7f9568fa86efcd3c86547baa0000b Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 14:34:58 -0300 Subject: [PATCH 100/153] fix(protocolStage): change picoc validation --- .../find/GetProtocolStageServiceImpl.kt | 19 ++++++++++++++----- .../find/GetProtocolStageServiceImplTest.kt | 8 +++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index f95e9c40d..cf1ccb02c 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -44,6 +44,7 @@ class GetProtocolStageServiceImpl( val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } val stage = evaluateStage(protocolDto, totalStudiesCount, includedStudiesCount, extractedStudiesCount) + println(stage) presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) } @@ -55,9 +56,18 @@ class GetProtocolStageServiceImpl( } val picoc = dto.picoc - if (picoc == null || (picoc.population.isNullOrBlank() && picoc.intervention.isNullOrBlank() && - picoc.control.isNullOrBlank() && picoc.outcome.isNullOrBlank() && picoc.context.isNullOrBlank())) { - return ProtocolStage.PICOC + val picocIsStarted = picoc != null && ( + !picoc.population.isNullOrBlank() || !picoc.intervention.isNullOrBlank() || + !picoc.control.isNullOrBlank() || !picoc.outcome.isNullOrBlank() || !picoc.context.isNullOrBlank() + ) + + if (picocIsStarted) { + val picocIsCompleted = !picoc!!.population.isNullOrBlank() && !picoc.intervention.isNullOrBlank() && + !picoc.control.isNullOrBlank() && !picoc.outcome.isNullOrBlank() && !picoc.context.isNullOrBlank() + + if (!picocIsCompleted) { + return ProtocolStage.PICOC + } } if (dto.studiesLanguages.isEmpty() && dto.eligibilityCriteria.isEmpty() && @@ -76,8 +86,7 @@ class GetProtocolStageServiceImpl( hasExclusionCriteria && dto.informationSources.isNotEmpty() - val areFinalFieldsFilled = dto.researchQuestions.isNotEmpty() && - !dto.analysisAndSynthesisProcess.isNullOrBlank() + val areFinalFieldsFilled = !dto.analysisAndSynthesisProcess.isNullOrBlank() if (!isSetupComplete || !areFinalFieldsFilled) { return ProtocolStage.PROTOCOL_PART_III diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt index 3f5ee9566..bee856a40 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -101,7 +101,13 @@ class GetProtocolStageServiceImplTest { systematicStudy = systematicStudyId, goal = "A goal", justification = "A justification", - picoc = null + picoc = PicocDto( + population = "P", + intervention = null, + control = null, + outcome = null, + context = null + ) ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() From a5cf5e231525e3c1cba0dfc05c2ad6c5a859eaac Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 15:03:58 -0300 Subject: [PATCH 101/153] fix(protocolStage): invert protocol part iii condition check --- .../application/protocol/find/GetProtocolStageServiceImpl.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index cf1ccb02c..4a5c5e2aa 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -44,7 +44,6 @@ class GetProtocolStageServiceImpl( val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } val stage = evaluateStage(protocolDto, totalStudiesCount, includedStudiesCount, extractedStudiesCount) - println(stage) presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) } @@ -86,7 +85,7 @@ class GetProtocolStageServiceImpl( hasExclusionCriteria && dto.informationSources.isNotEmpty() - val areFinalFieldsFilled = !dto.analysisAndSynthesisProcess.isNullOrBlank() + val areFinalFieldsFilled = dto.researchQuestions.isNotEmpty() && dto.analysisAndSynthesisProcess.isNullOrBlank() if (!isSetupComplete || !areFinalFieldsFilled) { return ProtocolStage.PROTOCOL_PART_III From 49995d3c590620663e0ea2db6da383ac30c76e3e Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 15:48:21 -0300 Subject: [PATCH 102/153] fix(protocolStage): separate protocol part iii condition into two different conditions --- .../protocol/find/GetProtocolStageServiceImpl.kt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index 4a5c5e2aa..273356714 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -85,9 +85,14 @@ class GetProtocolStageServiceImpl( hasExclusionCriteria && dto.informationSources.isNotEmpty() - val areFinalFieldsFilled = dto.researchQuestions.isNotEmpty() && dto.analysisAndSynthesisProcess.isNullOrBlank() + if (!isSetupComplete) { + return ProtocolStage.PROTOCOL_PART_III + } + + val areFinalFieldsEmpty = dto.researchQuestions.isEmpty() && + dto.analysisAndSynthesisProcess.isNullOrBlank() - if (!isSetupComplete || !areFinalFieldsFilled) { + if (areFinalFieldsEmpty) { return ProtocolStage.PROTOCOL_PART_III } From 10f1a3f1b069ed600302517cb35b738af0fbcdee Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Wed, 2 Jul 2025 16:06:47 -0300 Subject: [PATCH 103/153] refactor(protocolStage): separate protocol part iii into two different condition gates --- .../find/GetProtocolStageServiceImpl.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index 273356714..b287a8ec9 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -79,20 +79,13 @@ class GetProtocolStageServiceImpl( val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } - val isSetupComplete = dto.extractionQuestions.isNotEmpty() && - dto.robQuestions.isNotEmpty() && - hasInclusionCriteria && + val isProtocolTextComplete = hasInclusionCriteria && hasExclusionCriteria && - dto.informationSources.isNotEmpty() + dto.informationSources.isNotEmpty() && + dto.researchQuestions.isNotEmpty() && + !dto.analysisAndSynthesisProcess.isNullOrBlank() - if (!isSetupComplete) { - return ProtocolStage.PROTOCOL_PART_III - } - - val areFinalFieldsEmpty = dto.researchQuestions.isEmpty() && - dto.analysisAndSynthesisProcess.isNullOrBlank() - - if (areFinalFieldsEmpty) { + if (!isProtocolTextComplete) { return ProtocolStage.PROTOCOL_PART_III } @@ -104,6 +97,13 @@ class GetProtocolStageServiceImpl( return ProtocolStage.SELECTION } + val areExtractionFormsDefined = dto.extractionQuestions.isNotEmpty() && + dto.robQuestions.isNotEmpty() + + if (!areExtractionFormsDefined) { + return ProtocolStage.PROTOCOL_PART_III + } + if (extractedStudiesCount == 0) { return ProtocolStage.EXTRACTION } From b355f68d8749bea4c82c76f1a59b6e8741641c1a Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 3 Jul 2025 14:56:49 -0300 Subject: [PATCH 104/153] refactor(protocolStage): change protocol part iii conditional logic --- .../protocol/find/GetProtocolStageServiceImpl.kt | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index b287a8ec9..39f17ff77 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -78,14 +78,15 @@ class GetProtocolStageServiceImpl( val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } + val extractionAndRobDefined = dto.extractionQuestions.isNotEmpty() && dto.robQuestions.isNotEmpty() + val hasDatabases = dto.informationSources.isNotEmpty() - val isProtocolTextComplete = hasInclusionCriteria && - hasExclusionCriteria && - dto.informationSources.isNotEmpty() && + val protocolPartIIICompleted = hasInclusionCriteria && hasExclusionCriteria && + extractionAndRobDefined && hasDatabases && dto.researchQuestions.isNotEmpty() && !dto.analysisAndSynthesisProcess.isNullOrBlank() - if (!isProtocolTextComplete) { + if (!protocolPartIIICompleted) { return ProtocolStage.PROTOCOL_PART_III } @@ -97,13 +98,6 @@ class GetProtocolStageServiceImpl( return ProtocolStage.SELECTION } - val areExtractionFormsDefined = dto.extractionQuestions.isNotEmpty() && - dto.robQuestions.isNotEmpty() - - if (!areExtractionFormsDefined) { - return ProtocolStage.PROTOCOL_PART_III - } - if (extractedStudiesCount == 0) { return ProtocolStage.EXTRACTION } From 2b8e6b6a018ee411e36dddb36b7703e0175cddda Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Thu, 3 Jul 2025 15:10:57 -0300 Subject: [PATCH 105/153] test(protocolStage): add controller tests for the stage endpoint --- .../controller/ProtocolControllerTest.kt | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt index e305b0a7e..b99006f85 100644 --- a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt +++ b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt @@ -65,6 +65,12 @@ class ProtocolControllerTest( private fun getUrl(systematicStudy: UUID = factory.protocol) = "/systematic-study/$systematicStudy/protocol" + private fun putUrl(systematicStudyId: UUID = factory.protocol) = + "/systematic-study/$systematicStudyId/protocol" + + private fun getStage(systematicStudy: UUID = factory.protocol) = + "/systematic-study/$systematicStudy/protocol/stage" + @Nested @DisplayName("When getting protocols") inner class WhenGettingProtocols { @@ -126,9 +132,6 @@ class ProtocolControllerTest( } } - private fun putUrl(systematicStudyId: UUID = factory.protocol) = - "/systematic-study/$systematicStudyId/protocol" - @Nested @DisplayName("When putting protocols") inner class WhenPuttingProtocols { @@ -255,4 +258,43 @@ class ProtocolControllerTest( } } } + + @Nested + @DisplayName("When getting protocol stage") + inner class WhenGettingProtocolStage { + @Test + fun `should return protocol stage with 200 status when protocol exists`() { + val document = factory.createProtocolDocument() + protocolRepository.save(document) + + mockMvc.perform(get(getStage()) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk) + .andExpect(jsonPath("$.systematicStudyId").value(factory.protocol.toString())) + .andExpect(jsonPath("$.currentStage").exists()) + } + + @Test + fun `should return 404 when protocol does not exist`() { + mockMvc.perform(get(getStage()) + .with(SecurityMockMvcRequestPostProcessors.user(user)) + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isNotFound) + .andExpect(jsonPath("$.message").exists()) + .andExpect(jsonPath("$.detail").exists()) + } + + @Test + fun `should not authorize researchers that are not collaborators to get protocol stage`() { + testHelperService.testForUnauthorizedUser(mockMvc, get(getStage())) + } + + @Test + fun `should not allow unauthenticated users to get protocol stage`() { + testHelperService.testForUnauthenticatedUser(mockMvc, get(getStage())) + } + } } \ No newline at end of file From c1ac0978b6ef6b0de7dfec83115d100d5cf12ac1 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Fri, 4 Jul 2025 12:55:57 -0300 Subject: [PATCH 106/153] build: change actions to main branch --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 733eec78e..b96aca1da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI with Maven 2025 on: push: - branches: [ "fix-pom" ] + branches: [ "main" ] pull_request: branches: [ "main" ] From 99b801c9db90ce9657766e0cedd11918cf001870 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Fri, 4 Jul 2025 13:52:13 -0300 Subject: [PATCH 107/153] fix: identification bug and add configuration --- .../find/GetProtocolStageServiceImpl.kt | 32 ++++++++++++++++--- .../ProtocolServicesConfiguration.kt | 11 +++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index 39f17ff77..4ee1e3cfc 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -7,10 +7,12 @@ import br.all.application.protocol.find.GetProtocolStageService.RequestModel import br.all.application.protocol.find.GetProtocolStageService.ResponseModel import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage import br.all.application.protocol.repository.ProtocolDto +import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.study.repository.StudyReviewRepository +import br.all.domain.model.question.QuestionContextEnum import br.all.domain.model.review.SystematicStudy import org.springframework.stereotype.Service @@ -19,7 +21,8 @@ class GetProtocolStageServiceImpl( private val protocolRepository: ProtocolRepository, private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, + private val questionRepository: QuestionRepository ) : GetProtocolStageService { override fun getStage(presenter: GetProtocolStagePresenter, request: RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() @@ -38,18 +41,33 @@ class GetProtocolStageServiceImpl( } val allStudies = studyReviewRepository.findAllFromReview(request.systematicStudyId) - + val robQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto!!.id, QuestionContextEnum.ROB).size + val extractionQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto.id, QuestionContextEnum.EXTRACTION).size val totalStudiesCount = allStudies.size val includedStudiesCount = allStudies.count { it.selectionStatus == "INCLUDED" } val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } - val stage = evaluateStage(protocolDto, totalStudiesCount, includedStudiesCount, extractedStudiesCount) + val stage = evaluateStage( + protocolDto, + totalStudiesCount, + includedStudiesCount, + extractedStudiesCount, + robQuestions, + extractionQuestions, + ) presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) } - private fun evaluateStage(dto: ProtocolDto, totalStudiesCount: Int, includedStudiesCount: Int, extractedStudiesCount: Int) : ProtocolStage { + private fun evaluateStage( + dto: ProtocolDto, + totalStudiesCount: Int, + includedStudiesCount: Int, + extractedStudiesCount: Int, + robQuestionCount: Int, + extractionQuestionsCount: Int + ): ProtocolStage { if (dto.goal.isNullOrBlank() && dto.justification.isNullOrBlank()) { return ProtocolStage.PROTOCOL_PART_I } @@ -78,7 +96,7 @@ class GetProtocolStageServiceImpl( val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } - val extractionAndRobDefined = dto.extractionQuestions.isNotEmpty() && dto.robQuestions.isNotEmpty() + val extractionAndRobDefined = isThereExtractionAndRobQuestions(robQuestionCount, extractionQuestionsCount) val hasDatabases = dto.informationSources.isNotEmpty() val protocolPartIIICompleted = hasInclusionCriteria && hasExclusionCriteria && @@ -108,4 +126,8 @@ class GetProtocolStageServiceImpl( // Finalization would be returned here once its criteria are defined. } + + private fun isThereExtractionAndRobQuestions(robQuestionCount: Int, extractionQuestionsCount: Int): Boolean { + return robQuestionCount > 0 && extractionQuestionsCount > 0 + } } \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt b/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt index 70923399e..11efb480f 100644 --- a/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt @@ -1,8 +1,10 @@ package br.all.protocol.controller import br.all.application.protocol.find.FindProtocolServiceImpl +import br.all.application.protocol.find.GetProtocolStageServiceImpl import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.update.UpdateProtocolServiceImpl +import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService @@ -27,4 +29,13 @@ class ProtocolServicesConfiguration { studyReviewRepository: StudyReviewRepository, scoreCalculatorService: ScoreCalculatorService ) = UpdateProtocolServiceImpl(protocolRepository, systematicStudyRepository, credentialsService, studyReviewRepository, scoreCalculatorService) + + @Bean + fun getProtocolStageService( + protocolRepository: ProtocolRepository, + systematicStudyRepository: SystematicStudyRepository, + studyReviewRepository: StudyReviewRepository, + credentialsService: CredentialsService, + questionRepository: QuestionRepository + ) = GetProtocolStageServiceImpl(protocolRepository, systematicStudyRepository, studyReviewRepository, credentialsService, questionRepository) } From 454ed5fdbabe80f2ebf151a1b0b4be6a9c94a6e8 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Fri, 4 Jul 2025 14:45:09 -0300 Subject: [PATCH 108/153] refactor(protocolStage): extract functions from condition for readability reasons --- .../find/GetProtocolStageServiceImpl.kt | 96 +++++++++---------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index 4ee1e3cfc..22403c249 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -26,7 +26,6 @@ class GetProtocolStageServiceImpl( ) : GetProtocolStageService { override fun getStage(presenter: GetProtocolStagePresenter, request: RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() - val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } @@ -43,6 +42,7 @@ class GetProtocolStageServiceImpl( val allStudies = studyReviewRepository.findAllFromReview(request.systematicStudyId) val robQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto!!.id, QuestionContextEnum.ROB).size val extractionQuestions = questionRepository.findAllBySystematicStudyId(systematicStudyDto.id, QuestionContextEnum.EXTRACTION).size + val totalStudiesCount = allStudies.size val includedStudiesCount = allStudies.count { it.selectionStatus == "INCLUDED" } val extractedStudiesCount = allStudies.count { it.extractionStatus == "INCLUDED" } @@ -59,7 +59,6 @@ class GetProtocolStageServiceImpl( presenter.prepareSuccessView(ResponseModel(request.userId, request.systematicStudyId, stage)) } - private fun evaluateStage( dto: ProtocolDto, totalStudiesCount: Int, @@ -68,66 +67,63 @@ class GetProtocolStageServiceImpl( robQuestionCount: Int, extractionQuestionsCount: Int ): ProtocolStage { - if (dto.goal.isNullOrBlank() && dto.justification.isNullOrBlank()) { - return ProtocolStage.PROTOCOL_PART_I + return when { + isProtocolPartI(dto) -> ProtocolStage.PROTOCOL_PART_I + picocStage(dto) -> ProtocolStage.PICOC + isProtocolPartII(dto) -> ProtocolStage.PROTOCOL_PART_II + !isProtocolPartIIICompleted(dto, robQuestionCount, extractionQuestionsCount) -> ProtocolStage.PROTOCOL_PART_III + totalStudiesCount == 0 -> ProtocolStage.IDENTIFICATION + includedStudiesCount == 0 -> ProtocolStage.SELECTION + extractedStudiesCount == 0 -> ProtocolStage.EXTRACTION + else -> ProtocolStage.GRAPHICS } + } - val picoc = dto.picoc - val picocIsStarted = picoc != null && ( - !picoc.population.isNullOrBlank() || !picoc.intervention.isNullOrBlank() || - !picoc.control.isNullOrBlank() || !picoc.outcome.isNullOrBlank() || !picoc.context.isNullOrBlank() - ) + private fun isProtocolPartI(dto: ProtocolDto): Boolean { + return dto.goal.isNullOrBlank() && dto.justification.isNullOrBlank() + } - if (picocIsStarted) { - val picocIsCompleted = !picoc!!.population.isNullOrBlank() && !picoc.intervention.isNullOrBlank() && - !picoc.control.isNullOrBlank() && !picoc.outcome.isNullOrBlank() && !picoc.context.isNullOrBlank() + private fun isProtocolPartII(dto: ProtocolDto): Boolean { + return dto.studiesLanguages.isEmpty() && + dto.eligibilityCriteria.isEmpty() && + dto.informationSources.isEmpty() && + dto.keywords.isEmpty() && + dto.sourcesSelectionCriteria.isNullOrBlank() && + dto.searchMethod.isNullOrBlank() && + dto.selectionProcess.isNullOrBlank() + } - if (!picocIsCompleted) { - return ProtocolStage.PICOC - } - } + private fun isProtocolPartIIICompleted(dto: ProtocolDto, robQuestionCount: Int, extractionQuestionsCount: Int): Boolean { + val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", ignoreCase = true) } + val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", ignoreCase = true) } - if (dto.studiesLanguages.isEmpty() && dto.eligibilityCriteria.isEmpty() && - dto.informationSources.isEmpty() && dto.keywords.isEmpty() && - dto.sourcesSelectionCriteria.isNullOrBlank() && dto.searchMethod.isNullOrBlank() && - dto.selectionProcess.isNullOrBlank()) { - return ProtocolStage.PROTOCOL_PART_II - } + val hasExtractionAndRob = robQuestionCount > 0 && extractionQuestionsCount > 0 - val hasInclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("INCLUSION", true) } - val hasExclusionCriteria = dto.eligibilityCriteria.any { it.type.equals("EXCLUSION", true) } - val extractionAndRobDefined = isThereExtractionAndRobQuestions(robQuestionCount, extractionQuestionsCount) val hasDatabases = dto.informationSources.isNotEmpty() + val hasResearchQuestions = dto.researchQuestions.isNotEmpty() + val hasAnalysisProcess = !dto.analysisAndSynthesisProcess.isNullOrBlank() - val protocolPartIIICompleted = hasInclusionCriteria && hasExclusionCriteria && - extractionAndRobDefined && hasDatabases && - dto.researchQuestions.isNotEmpty() && - !dto.analysisAndSynthesisProcess.isNullOrBlank() + return hasInclusionCriteria && hasExclusionCriteria && + hasExtractionAndRob && hasDatabases && + hasResearchQuestions && hasAnalysisProcess + } - if (!protocolPartIIICompleted) { - return ProtocolStage.PROTOCOL_PART_III - } + private fun picocStage(dto: ProtocolDto): Boolean { + val picoc = dto.picoc + if (picoc == null) return false - if (totalStudiesCount == 0) { - return ProtocolStage.IDENTIFICATION - } + val picocIsStarted = !picoc.population.isNullOrBlank() || !picoc.intervention.isNullOrBlank() || + !picoc.control.isNullOrBlank() || !picoc.outcome.isNullOrBlank() || !picoc.context.isNullOrBlank() - if (includedStudiesCount == 0) { - return ProtocolStage.SELECTION - } + if (picocIsStarted) { + val picocIsCompleted = !picoc.population.isNullOrBlank() && !picoc.intervention.isNullOrBlank() && + !picoc.control.isNullOrBlank() && !picoc.outcome.isNullOrBlank() && !picoc.context.isNullOrBlank() - if (extractedStudiesCount == 0) { - return ProtocolStage.EXTRACTION + if (!picocIsCompleted) { + return true + } } - // This stage is reached when extraction is complete, but finalization has not yet begun. - // As Finalization criteria are not yet defined, this is the default final step. - return ProtocolStage.GRAPHICS - - // Finalization would be returned here once its criteria are defined. - } - - private fun isThereExtractionAndRobQuestions(robQuestionCount: Int, extractionQuestionsCount: Int): Boolean { - return robQuestionCount > 0 && extractionQuestionsCount > 0 + return false } -} \ No newline at end of file +} From a627b954716f46d46b8313cf16b200a824f5ecef Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Fri, 4 Jul 2025 14:45:19 -0300 Subject: [PATCH 109/153] test(protocolStage): fix broken tests after refactoring --- .../find/GetProtocolStageServiceImplTest.kt | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt index bee856a40..37c359294 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -3,6 +3,7 @@ package br.all.application.protocol.find import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.util.TestDataFactory as ProtocolFactory import br.all.application.study.util.TestDataFactory as StudyReviewFactory +import br.all.application.question.util.TestDataFactory as QuestionFactory import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService @@ -23,6 +24,8 @@ import br.all.application.protocol.find.GetProtocolStageService.ResponseModel import br.all.application.protocol.find.GetProtocolStageService.ProtocolStage import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.PicocDto +import br.all.application.question.repository.QuestionRepository +import br.all.domain.model.question.QuestionContextEnum import io.mockk.verify @Tag("UnitTest") @@ -39,6 +42,9 @@ class GetProtocolStageServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var studyReviewRepository: StudyReviewRepository + @MockK(relaxUnitFun = true) + private lateinit var questionRepository: QuestionRepository + @MockK private lateinit var credentialsService: CredentialsService @@ -51,6 +57,7 @@ class GetProtocolStageServiceImplTest { private lateinit var precondition: PreconditionCheckerMockingNew private lateinit var protocolFactory: ProtocolFactory private lateinit var studyReviewFactory: StudyReviewFactory + private lateinit var questionFactory: QuestionFactory private lateinit var researcherId: UUID private lateinit var systematicStudyId: UUID @@ -59,6 +66,7 @@ class GetProtocolStageServiceImplTest { fun setup() { protocolFactory = ProtocolFactory() studyReviewFactory = StudyReviewFactory() + questionFactory = QuestionFactory() researcherId = protocolFactory.researcher systematicStudyId = protocolFactory.systematicStudy @@ -84,8 +92,11 @@ class GetProtocolStageServiceImplTest { goal = null, justification = null ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() val request = RequestModel(researcherId, systematicStudyId) @@ -109,8 +120,11 @@ class GetProtocolStageServiceImplTest { context = null ) ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() val request = RequestModel(researcherId, systematicStudyId) @@ -132,8 +146,11 @@ class GetProtocolStageServiceImplTest { informationSources = emptySet(), keywords = emptySet() ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() val request = RequestModel(researcherId, systematicStudyId) @@ -153,8 +170,11 @@ class GetProtocolStageServiceImplTest { keywords = setOf("test"), extractionQuestions = emptySet() ) + every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns emptyList() val request = RequestModel(researcherId, systematicStudyId) @@ -167,9 +187,14 @@ class GetProtocolStageServiceImplTest { @Test fun `should return IDENTIFICATION stage when no studies have been submitted`() { val protocolDto = createFullProtocolDto() + val questions = listOf( + questionFactory.generateTextualDto() + ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns emptyList() + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions val request = RequestModel(researcherId, systematicStudyId) @@ -182,13 +207,17 @@ class GetProtocolStageServiceImplTest { @Test fun `should return SELECTION stage when studies exist but none are included`() { val protocolDto = createFullProtocolDto() - val studies = listOf( - createFullStudyReviewDto(selectionStatus = "REJECTED", extractionStatus = "PENDING") + createFullStudyReviewDto(selectionStatus = "", extractionStatus = "") + ) + val questions = listOf( + questionFactory.generateTextualDto() ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions val request = RequestModel(researcherId, systematicStudyId) @@ -201,13 +230,17 @@ class GetProtocolStageServiceImplTest { @Test fun `should return EXTRACTION stage when studies are included but none are extracted`() { val protocolDto = createFullProtocolDto() - val studies = listOf( - createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "PENDING") + createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "") + ) + val questions = listOf( + questionFactory.generateTextualDto() ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions val request = RequestModel(researcherId, systematicStudyId) @@ -220,13 +253,17 @@ class GetProtocolStageServiceImplTest { @Test fun `should return GRAPHICS stage when studies have been extracted`() { val protocolDto = createFullProtocolDto() - val studies = listOf( createFullStudyReviewDto(selectionStatus = "INCLUDED", extractionStatus = "INCLUDED") ) + val questions = listOf( + questionFactory.generateTextualDto() + ) every { protocolRepository.findById(systematicStudyId) } returns protocolDto every { studyReviewRepository.findAllFromReview(systematicStudyId) } returns studies + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.ROB) } returns questions + every { questionRepository.findAllBySystematicStudyId(systematicStudyId, QuestionContextEnum.EXTRACTION) } returns questions val request = RequestModel(researcherId, systematicStudyId) @@ -237,6 +274,7 @@ class GetProtocolStageServiceImplTest { } } + private fun createFullProtocolDto() = protocolFactory.protocolDto( systematicStudy = systematicStudyId, goal = "A goal", From eb3cdcbc8ae1467e604694aebf09e1c42e36b430 Mon Sep 17 00:00:00 2001 From: matheusspacifico Date: Fri, 4 Jul 2025 14:47:25 -0300 Subject: [PATCH 110/153] feat(batchAnswer): add controller configuration for batch endpoint --- .../controller/StudyReviewServicesConfiguration.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt index 95ff740fd..ea5d2acd6 100644 --- a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt @@ -139,6 +139,19 @@ class StudyReviewServicesConfiguration { credentialsService ) + @Bean + fun batchAnswerQuestionService( + studyReviewRepository: StudyReviewRepository, + questionRepository: QuestionRepository, + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService + ) = BatchAnswerQuestionServiceImpl( + studyReviewRepository, + questionRepository, + systematicStudyRepository, + credentialsService + ) + @Bean fun removeCriteriaService( studyReviewRepository: StudyReviewRepository, From f5977e5ffa3c60c8c0e0de603f26a7868307bfc9 Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:10:32 -0300 Subject: [PATCH 111/153] refactor: improve deleteSearchSessionServiceImpl by adding existence check before fetching session --- .../delete/DeleteSearchSessionPresenter.kt | 4 +- .../delete/DeleteSearchSessionService.kt | 10 +++-- .../delete/DeleteSearchSessionServiceImpl.kt | 42 +++++++++++-------- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt index a202c3eca..e9ef45ad2 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionPresenter.kt @@ -1,6 +1,6 @@ package br.all.application.search.delete -import br.all.application.shared.presenter.GenericPresenter import br.all.application.search.delete.DeleteSearchSessionService.ResponseModel +import br.all.application.shared.presenter.GenericPresenter -interface DeleteSearchSessionPresenter: GenericPresenter \ No newline at end of file +interface DeleteSearchSessionPresenter : GenericPresenter diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt index 686fb3abe..2067d589a 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionService.kt @@ -1,11 +1,15 @@ +@file:Suppress("ktlint:standard:no-wildcard-imports") + package br.all.application.search.delete -import br.all.application.search.update.PatchSearchSessionPresenter import io.swagger.v3.oas.annotations.media.Schema import java.util.* interface DeleteSearchSessionService { - fun delete(presenter: DeleteSearchSessionPresenter, request: RequestModel) + fun delete( + presenter: DeleteSearchSessionPresenter, + request: RequestModel, + ) data class RequestModel( val userId: UUID, @@ -19,4 +23,4 @@ interface DeleteSearchSessionService { val systematicStudyId: UUID, val sessionId: UUID, ) -} \ No newline at end of file +} diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt index 93c25f35c..bce8b23c3 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt @@ -8,38 +8,46 @@ import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.user.CredentialsService import br.all.domain.model.review.SystematicStudy -class DeleteSearchSessionServiceImpl ( +class DeleteSearchSessionServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, ) : DeleteSearchSessionService { override fun delete( presenter: DeleteSearchSessionPresenter, - request: DeleteSearchSessionService.RequestModel + request: DeleteSearchSessionService.RequestModel, ) { val user = credentialsService.loadCredentials(request.userId)?.toUser() - - val searchSessionDto = searchSessionRepository.findById(request.sessionId) - val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) - val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val systematicStudy = + systematicStudyRepository + .findById( + request.systematicStudyId, + )?.let { + SystematicStudy.fromDto(it) + } presenter.prepareIfFailsPreconditions(user, systematicStudy) if (presenter.isDone()) return - if (searchSessionDto != null) { - searchSessionRepository.deleteById(searchSessionDto.id) - - presenter.prepareSuccessView( - DeleteSearchSessionService.ResponseModel( - userId = request.userId, - systematicStudyId = request.systematicStudyId, - sessionId = request.sessionId + if (searchSessionRepository.existsById(request.sessionId)) { + val searchSessionDto = searchSessionRepository.findById(request.sessionId) + if (searchSessionDto != null) { + searchSessionRepository.deleteById(searchSessionDto.id) + presenter.prepareSuccessView( + DeleteSearchSessionService.ResponseModel( + userId = request.userId, + systematicStudyId = request.systematicStudyId, + sessionId = request.sessionId, + ), ) - ) + } else { + val message = "There is no search session with ID ${request.sessionId}" + presenter.prepareFailView(EntityNotFoundException(message)) + } } else { val message = "There is no search session with ID ${request.sessionId}" presenter.prepareFailView(EntityNotFoundException(message)) } } -} \ No newline at end of file +} From 3bae67736fd343ce7c8df753a0dc67b2aeff9c3a Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 5 Mar 2025 18:43:04 -0300 Subject: [PATCH 112/153] refactor: improve logic by removing unnecessary query and inverting if clause --- .../delete/DeleteSearchSessionServiceImpl.kt | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt index bce8b23c3..9e2c3bdca 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt @@ -30,24 +30,20 @@ class DeleteSearchSessionServiceImpl( if (presenter.isDone()) return - if (searchSessionRepository.existsById(request.sessionId)) { - val searchSessionDto = searchSessionRepository.findById(request.sessionId) - if (searchSessionDto != null) { - searchSessionRepository.deleteById(searchSessionDto.id) - presenter.prepareSuccessView( - DeleteSearchSessionService.ResponseModel( - userId = request.userId, - systematicStudyId = request.systematicStudyId, - sessionId = request.sessionId, - ), - ) - } else { - val message = "There is no search session with ID ${request.sessionId}" - presenter.prepareFailView(EntityNotFoundException(message)) - } - } else { - val message = "There is no search session with ID ${request.sessionId}" - presenter.prepareFailView(EntityNotFoundException(message)) + val searchSessionDto = searchSessionRepository.findById(request.sessionId) + + if(searchSessionDto == null){ + presenter.prepareFailView(EntityNotFoundException("There is no search session with ID ${request.sessionId}")) + return } + + searchSessionRepository.deleteById(searchSessionDto.id) + presenter.prepareSuccessView( + DeleteSearchSessionService.ResponseModel( + userId = request.userId, + systematicStudyId = request.systematicStudyId, + sessionId = request.sessionId, + ), + ) } } From 55f655cd7783698a559271bb63fb1141b1f7f9aa Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:21:03 -0300 Subject: [PATCH 113/153] test: add unit tests for deleteSearchSessionServiceImpl --- .../DeleteSearchSessionServiceImplTest.kt | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt diff --git a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt new file mode 100644 index 000000000..5050a9dc5 --- /dev/null +++ b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt @@ -0,0 +1,141 @@ +@file:Suppress("ktlint:standard:no-wildcard-imports") + +package br.all.application.search.delete + +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.search.repository.SearchSessionRepository +import br.all.application.search.util.TestDataFactory +import br.all.application.shared.exceptions.EntityNotFoundException +import br.all.application.shared.exceptions.UnauthenticatedUserException +import br.all.application.shared.exceptions.UnauthorizedUserException +import br.all.application.user.CredentialsService +import br.all.application.util.PreconditionCheckerMockingNew +import io.mockk.* +import io.mockk.impl.annotations.InjectMockKs +import io.mockk.impl.annotations.MockK +import io.mockk.junit5.MockKExtension +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(MockKExtension::class) +class DeleteSearchSessionServiceImplTest { + @MockK(relaxUnitFun = true) + private lateinit var systematicStudyRepository: SystematicStudyRepository + + @MockK(relaxUnitFun = true) + private lateinit var searchSessionRepository: SearchSessionRepository + + @MockK(relaxed = true) + private lateinit var presenter: DeleteSearchSessionPresenter + + @MockK + private lateinit var credentialService: CredentialsService + + @InjectMockKs + private lateinit var sut: DeleteSearchSessionServiceImpl + + private lateinit var factory: TestDataFactory + private lateinit var preconditionCheckerMocking: PreconditionCheckerMockingNew + + @BeforeEach + fun setUp() { + factory = TestDataFactory() + preconditionCheckerMocking = + PreconditionCheckerMockingNew( + presenter, + credentialService, + systematicStudyRepository, + factory.userId, + factory.systematicStudyId, + ) + } + + @Nested + @DisplayName("When successfully deleting search session") + inner class WhenSuccessfullyDeletingSearchSession { + @BeforeEach + fun setUp() { + preconditionCheckerMocking.makeEverythingWork() + } + + @Test + fun `should successfully delete search session`() { + val request = factory.deleteRequestModel() + val response = factory.deleteResponseModel() + + every { searchSessionRepository.existsById(factory.searchSessionId) } returns true + every { searchSessionRepository.findById(factory.searchSessionId) } returns factory.generateDto() + every { searchSessionRepository.deleteById(factory.searchSessionId) } just Runs + + sut.delete(presenter, request) + + verify { + searchSessionRepository.deleteById(factory.searchSessionId) + presenter.prepareSuccessView(response) + } + } + } + + @Nested + @DisplayName("When unable to delete search session") + inner class WhenUnableToDeleteSearchSession { + @Test + fun `should fail with EntityNotFoundException when session does not exist`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeEverythingWork() + every { searchSessionRepository.existsById(factory.searchSessionId) } returns false + every { searchSessionRepository.findById(factory.searchSessionId) } returns null + + sut.delete(presenter, request) + + verify { + searchSessionRepository.existsById(factory.searchSessionId) + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should the researcher be unauthorized if they are not a collaborator`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthorized() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should prepare fail view if the researcher is unauthenticated`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthenticated() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + + @Test + fun `should prepare fail view if the researcher is unauthorized`() { + val request = factory.deleteRequestModel() + + preconditionCheckerMocking.makeUserUnauthorized() + sut.delete(presenter, request) + + verifyOrder { + presenter.prepareFailView(any()) + presenter.isDone() + } + } + } +} From cf438cbf590ad7bc219c905ae9b3ef27387eef8b Mon Sep 17 00:00:00 2001 From: vmacena Date: Wed, 5 Mar 2025 12:28:13 -0300 Subject: [PATCH 114/153] test: add deleteRequestModel and deleteResponseModel methods to testDataFactory --- .../search/util/TestDataFactory.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt index a574db434..3053801d0 100644 --- a/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/search/util/TestDataFactory.kt @@ -3,6 +3,7 @@ package br.all.application.search.util import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.PicocDto import br.all.application.protocol.repository.ProtocolDto +import br.all.application.search.delete.DeleteSearchSessionService import br.all.application.search.find.service.FindAllSearchSessionsBySourceService import br.all.application.search.find.service.FindAllSearchSessionsService import br.all.application.search.find.service.FindSearchSessionService @@ -64,6 +65,26 @@ class TestDataFactory { invalidEntries: List = emptyList() ) = CreateResponseModel(userId, systematicStudyId, sessionId, invalidEntries) + fun deleteRequestModel( + userId: UUID = this.userId, + systematicStudyId: UUID = this.systematicStudyId, + sessionId: UUID = this.searchSessionId, + ) = DeleteSearchSessionService.RequestModel( + userId, + systematicStudyId, + sessionId, + ) + + fun deleteResponseModel( + userId: UUID = this.userId, + systematicStudyId: UUID = this.systematicStudyId, + sessionId: UUID = this.searchSessionId, + ) = DeleteSearchSessionService.ResponseModel( + userId, + systematicStudyId, + sessionId, + ) + fun findOneRequestModel( userId: UUID = this.userId, systematicStudyId: UUID = this.systematicStudyId, From b1dfbb74e9bcf08203f84688de1f2ae21171f9c0 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 5 Mar 2025 18:50:30 -0300 Subject: [PATCH 115/153] test: remove unused function from tests --- .../search/delete/DeleteSearchSessionServiceImplTest.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt index 5050a9dc5..265f33150 100644 --- a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt @@ -66,7 +66,6 @@ class DeleteSearchSessionServiceImplTest { val request = factory.deleteRequestModel() val response = factory.deleteResponseModel() - every { searchSessionRepository.existsById(factory.searchSessionId) } returns true every { searchSessionRepository.findById(factory.searchSessionId) } returns factory.generateDto() every { searchSessionRepository.deleteById(factory.searchSessionId) } just Runs @@ -87,13 +86,11 @@ class DeleteSearchSessionServiceImplTest { val request = factory.deleteRequestModel() preconditionCheckerMocking.makeEverythingWork() - every { searchSessionRepository.existsById(factory.searchSessionId) } returns false every { searchSessionRepository.findById(factory.searchSessionId) } returns null sut.delete(presenter, request) verify { - searchSessionRepository.existsById(factory.searchSessionId) presenter.prepareFailView(any()) presenter.isDone() } From 373f4549dabda07dac92928e9913091a9cdf9751 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 19:28:36 -0300 Subject: [PATCH 116/153] feat: create collaboration document --- .../collaboration/CollaborationDocument.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt new file mode 100644 index 000000000..f7519c32f --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt @@ -0,0 +1,14 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +import java.util.* + +@Document("collaboration") +data class CollaborationDocument( + @Id val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val status: String, + val permissions: List +) From 891430ef833a117c7d49afa7637465e14775787d Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 19:57:17 -0300 Subject: [PATCH 117/153] feat: create invite document --- .../infrastructure/collaboration/InviteDocument.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt new file mode 100644 index 000000000..cb53006d5 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -0,0 +1,14 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.mapping.Document +import java.util.* + +@Document("invite") +data class InviteDocument( + @Id val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val inviteDate: Date, + val expirationDate: Date, +) From d7bc82c87cb9b5522ebb5d6a546a52852e8181bd Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:20:16 -0300 Subject: [PATCH 118/153] feat: define base of collaboration entity --- .../model/collaboration/Collaboration.kt | 16 ++++++++++++++ .../model/collaboration/CollaborationId.kt | 21 +++++++++++++++++++ .../collaboration/CollaborationPermission.kt | 7 +++++++ .../collaboration/CollaborationStatus.kt | 8 +++++++ .../collaboration/CollaborationDocument.kt | 2 +- 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt new file mode 100644 index 000000000..4fb768ce0 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -0,0 +1,16 @@ +package br.all.domain.model.collaboration + +import br.all.domain.model.review.SystematicStudyId +import br.all.domain.shared.ddd.Entity +import br.all.domain.user.UserAccountId +import java.util.UUID + +class Collaboration( + id: CollaborationId, + title: String, + systematicStudyId: SystematicStudyId, + userId: UserAccountId, + status: CollaborationStatus, + permissions: Set = emptySet() + ): Entity(id) { +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt new file mode 100644 index 000000000..104134f9c --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt @@ -0,0 +1,21 @@ +package br.all.domain.model.collaboration + +import br.all.domain.shared.ddd.Identifier +import br.all.domain.shared.ddd.Notification +import java.util.* + +@JvmInline +value class CollaborationId(private val value: UUID) : Identifier { + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + override fun validate() = Notification() + + override fun value() = value + + override fun toString() = value.toString() +} + +fun UUID.toCollaborationId() = CollaborationId(this) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt new file mode 100644 index 000000000..9f87ac2f9 --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationPermission.kt @@ -0,0 +1,7 @@ +package br.all.domain.model.collaboration + +enum class CollaborationPermission { + EDIT, + REVIEW_STUDIES, + VIEW +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt new file mode 100644 index 000000000..698aa33ed --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt @@ -0,0 +1,8 @@ +package br.all.domain.model.collaboration + +enum class CollaborationStatus { + INVITED, + REFUSED, + REMOVED, + ACTIVE +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt index f7519c32f..99f6ff6b7 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationDocument.kt @@ -10,5 +10,5 @@ data class CollaborationDocument( val systematicStudyId: UUID, val userId: UUID, val status: String, - val permissions: List + val permissions: Set = emptySet() ) From d9e4106eede3738a8b3e0a257076ac393e83b49b Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:20:29 -0300 Subject: [PATCH 119/153] feat: define base of invite entity --- .../all/domain/model/collaboration/Invite.kt | 15 +++++++++++++ .../domain/model/collaboration/InviteId.kt | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt create mode 100644 review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt new file mode 100644 index 000000000..59e038d1c --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -0,0 +1,15 @@ +package br.all.domain.model.collaboration + +import br.all.domain.model.review.SystematicStudyId +import br.all.domain.shared.ddd.Entity +import br.all.domain.user.UserAccountId +import java.util.* + +class Invite( + id: InviteId, + systematicStudyId: SystematicStudyId, + userId: UserAccountId, + inviteDate: Date, + expirationDate: Date +) : Entity(id) { +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt new file mode 100644 index 000000000..cc045b88d --- /dev/null +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/InviteId.kt @@ -0,0 +1,21 @@ +package br.all.domain.model.collaboration + +import br.all.domain.shared.ddd.Identifier +import br.all.domain.shared.ddd.Notification +import java.util.* + +@JvmInline +value class InviteId(private val value: UUID) : Identifier { + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + override fun validate() = Notification() + + override fun value() = value + + override fun toString() = value.toString() +} + +fun UUID.toInviteId() = InviteId(this) \ No newline at end of file From 1bafc28444d635705ec5efdd4c8c02de880063f9 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 20:21:51 -0300 Subject: [PATCH 120/153] feat: remove unused status values --- .../br/all/domain/model/collaboration/CollaborationStatus.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt index 698aa33ed..d48c3431c 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationStatus.kt @@ -1,8 +1,6 @@ package br.all.domain.model.collaboration enum class CollaborationStatus { - INVITED, - REFUSED, REMOVED, ACTIVE } \ No newline at end of file From 4ee854be70d5656e10991caa37d2d189dae8344b Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 21:27:33 -0300 Subject: [PATCH 121/153] feat: change invite dates to LocalDateTime --- .../model/collaboration/Collaboration.kt | 30 ++++++++++++++++--- .../all/domain/model/collaboration/Invite.kt | 7 +++-- .../collaboration/InviteDocument.kt | 5 ++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index 4fb768ce0..f6648ccbd 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -2,15 +2,37 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity +import br.all.domain.shared.ddd.Notification import br.all.domain.user.UserAccountId import java.util.UUID class Collaboration( id: CollaborationId, - title: String, - systematicStudyId: SystematicStudyId, - userId: UserAccountId, - status: CollaborationStatus, + val systematicStudyId: SystematicStudyId, + val userId: UserAccountId, + status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { + init{ + + } + + private val _permissions = permissions.toMutableSet() + val permissions get() = _permissions + + var status = status + private set + + fun addPermission(permission: CollaborationPermission) = _permissions.add(permission) + + fun removePermission(permission: CollaborationPermission) = _permissions.remove(permission) + + fun removeCollaboration() { + status = CollaborationStatus.REMOVED + } + + private fun validate() = Notification().also{ + if(permissions.isEmpty()) + it.addError("Collaboration must have at least one permission") + } } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 59e038d1c..f9436742f 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -3,13 +3,14 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity import br.all.domain.user.UserAccountId +import java.time.LocalDateTime import java.util.* class Invite( id: InviteId, systematicStudyId: SystematicStudyId, - userId: UserAccountId, - inviteDate: Date, - expirationDate: Date + userId: UserAccountId, + inviteDate: LocalDateTime, + expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt index cb53006d5..086d2276f 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -2,6 +2,7 @@ package br.all.infrastructure.collaboration import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.mapping.Document +import java.time.LocalDateTime import java.util.* @Document("invite") @@ -9,6 +10,6 @@ data class InviteDocument( @Id val id: UUID, val systematicStudyId: UUID, val userId: UUID, - val inviteDate: Date, - val expirationDate: Date, + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime, ) From c1b909a0855d9952f432e05b7d0a6b505282ebfa Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Mon, 7 Apr 2025 21:57:33 -0300 Subject: [PATCH 122/153] feat: implement init clauses --- .../kotlin/br/all/domain/model/collaboration/Collaboration.kt | 4 +++- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index f6648ccbd..ad4e92016 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -13,8 +13,10 @@ class Collaboration( status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { + init{ - + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } } private val _permissions = permissions.toMutableSet() diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index f9436742f..fcacce0e6 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -13,4 +13,8 @@ class Invite( inviteDate: LocalDateTime, expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { + + init{ + require(expirationDate.isAfter(inviteDate)) + } } \ No newline at end of file From 4bf9db1f39dd1c0984cef8eaaab95a9cdd0d85a9 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 9 Apr 2025 19:57:16 -0300 Subject: [PATCH 123/153] feat: add validation to invite entity --- .../br/all/domain/model/collaboration/Invite.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index fcacce0e6..c654b0160 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -2,6 +2,7 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId import br.all.domain.shared.ddd.Entity +import br.all.domain.shared.ddd.Notification import br.all.domain.user.UserAccountId import java.time.LocalDateTime import java.util.* @@ -10,11 +11,17 @@ class Invite( id: InviteId, systematicStudyId: SystematicStudyId, userId: UserAccountId, - inviteDate: LocalDateTime, - expirationDate: LocalDateTime = inviteDate.plusDays(30) + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { - - init{ - require(expirationDate.isAfter(inviteDate)) + + init { + val notification = validate() + require(notification.hasNoErrors()) { notification.message() } + } + + fun validate() = Notification().also { + if (inviteDate.isAfter(expirationDate)) + it.addError("Invite date cannot be after expiration date") } } \ No newline at end of file From 2a11d46fb20d4b9a6fc6785119a772a8244a946b Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Wed, 9 Apr 2025 21:33:58 -0300 Subject: [PATCH 124/153] feat: create collaboration repository and its implementation --- .../repository/CollaborationDto.kt | 11 +++++ .../repository/CollaborationRepository.kt | 11 +++++ .../collaboration/repository/InviteDto.kt | 12 +++++ .../collaboration/repository/InviteMapper.kt | 2 + .../all/domain/model/collaboration/Invite.kt | 4 +- .../CollaborationRepositoryImpl.kt | 45 +++++++++++++++++++ .../MongoCollaborationRepository.kt | 6 +++ .../collaboration/MongoInviteRepository.kt | 6 +++ 8 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt create mode 100644 review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt new file mode 100644 index 000000000..34a74c3f9 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationDto.kt @@ -0,0 +1,11 @@ +package br.all.application.collaboration.repository + +import java.util.* + +class CollaborationDto ( + val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val status: String, + val permissions: Set +) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt new file mode 100644 index 000000000..7896877dd --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt @@ -0,0 +1,11 @@ +package br.all.application.collaboration.repository + +import java.util.* + +interface CollaborationRepository { + fun saveOrUpdateCollaboration(dto: CollaborationDto) + fun saveOrUpdateInvite(dto: InviteDto) + + fun listAllCollaborationsBySystematicStudyId(id: UUID): List + fun listAllInvitesBySystematicStudyId(id: UUID): List +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt new file mode 100644 index 000000000..609610c03 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt @@ -0,0 +1,12 @@ +package br.all.application.collaboration.repository + +import java.time.LocalDateTime +import java.util.* + +class InviteDto ( + val id: UUID, + val systematicStudyId: UUID, + val userId: UUID, + val inviteDate: LocalDateTime, + val expirationDate: LocalDateTime +) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt new file mode 100644 index 000000000..2cf3ede6f --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt @@ -0,0 +1,2 @@ +package br.all.application.collaboration.repository + diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index c654b0160..931280ee6 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -9,8 +9,8 @@ import java.util.* class Invite( id: InviteId, - systematicStudyId: SystematicStudyId, - userId: UserAccountId, + val systematicStudyId: SystematicStudyId, + val userId: UserAccountId, val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt new file mode 100644 index 000000000..664db2977 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -0,0 +1,45 @@ +package br.all.infrastructure.collaboration + +import br.all.application.collaboration.repository.CollaborationDto +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.InviteDto +import java.util.* + +class CollaborationRepositoryImpl( + private val innerCollaborationRepository: MongoCollaborationRepository, + private val innerInviteRepository: MongoInviteRepository +) + : CollaborationRepository +{ + override fun saveOrUpdateCollaboration(dto: CollaborationDto) { + innerCollaborationRepository.save(CollaborationDocument( + dto.id, + dto.systematicStudyId, + dto.userId, + dto.status, + dto.permissions + )) + } + + override fun saveOrUpdateInvite(dto: InviteDto) { + innerInviteRepository.save(InviteDocument( + dto.id, + dto.systematicStudyId, + dto.userId, + dto.inviteDate, + dto.expirationDate + )) + } + + override fun listAllCollaborationsBySystematicStudyId(id: UUID): List { + return innerCollaborationRepository.findAll().filter { it.systematicStudyId == id }.map { + CollaborationDto(it.id, it.systematicStudyId, it.userId, it.status, it.permissions) + } + } + + override fun listAllInvitesBySystematicStudyId(id: UUID): List { + return innerInviteRepository.findAll().filter { it.systematicStudyId == id }.map { + InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate) + } + } +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt new file mode 100644 index 000000000..043e6c494 --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoCollaborationRepository.kt @@ -0,0 +1,6 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.mongodb.repository.MongoRepository +import java.util.* + +interface MongoCollaborationRepository: MongoRepository \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt new file mode 100644 index 000000000..05358d9fe --- /dev/null +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/MongoInviteRepository.kt @@ -0,0 +1,6 @@ +package br.all.infrastructure.collaboration + +import org.springframework.data.mongodb.repository.MongoRepository +import java.util.* + +interface MongoInviteRepository: MongoRepository \ No newline at end of file From 637b09487aba303b92e8323aa19edbf1aaf539ab Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:06:20 -0300 Subject: [PATCH 125/153] feat: reimplement exception handler using existing exception mapper --- .../kotlin/br/all/shared/error/ApiExceptionHandler.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt index 8d86cb6a1..ee74206d8 100644 --- a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt +++ b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt @@ -9,10 +9,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler @ControllerAdvice class ApiExceptionHandler { - @ExceptionHandler(value = [IllegalArgumentException::class]) - fun handleIllegalArgumentException(e: IllegalArgumentException): ResponseEntity<*> { - val status = HttpStatus.BAD_REQUEST - val apiException = ErrorMessage(status, e) - return ResponseEntity(apiException, status) + @ExceptionHandler(value = [RuntimeException::class]) + fun handleRuntimeException(exception: RuntimeException): ResponseEntity<*> { + return createErrorResponseFrom(throwable = exception) } } \ No newline at end of file From 7c410ac02eeff1543af439f7b420c1d71e1d9b7f Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:07:05 -0300 Subject: [PATCH 126/153] feat: change userId to use ResearcherId --- .../br/all/domain/model/collaboration/Collaboration.kt | 6 +++--- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt index ad4e92016..cc11c61e0 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Collaboration.kt @@ -1,15 +1,15 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId +import br.all.domain.model.user.ResearcherId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification -import br.all.domain.user.UserAccountId -import java.util.UUID +import java.util.* class Collaboration( id: CollaborationId, val systematicStudyId: SystematicStudyId, - val userId: UserAccountId, + val userId: ResearcherId, status: CollaborationStatus = CollaborationStatus.ACTIVE, permissions: Set = emptySet() ): Entity(id) { diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 931280ee6..67d23d287 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -1,16 +1,16 @@ package br.all.domain.model.collaboration import br.all.domain.model.review.SystematicStudyId +import br.all.domain.model.user.ResearcherId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification -import br.all.domain.user.UserAccountId import java.time.LocalDateTime import java.util.* class Invite( id: InviteId, val systematicStudyId: SystematicStudyId, - val userId: UserAccountId, + val userId: ResearcherId, val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { From 47af86c91dd9cd9287baf674dff35bea888196d6 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:07:30 -0300 Subject: [PATCH 127/153] feat: change SystematicStudy collaborator ids to CollaborationId --- .../collaboration/repository/InviteMapper.kt | 2 -- .../domain/model/review/SystematicStudy.kt | 24 +++++++++---------- 2 files changed, 12 insertions(+), 14 deletions(-) delete mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt deleted file mode 100644 index 2cf3ede6f..000000000 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteMapper.kt +++ /dev/null @@ -1,2 +0,0 @@ -package br.all.application.collaboration.repository - diff --git a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt index 6ff248e6e..f4efb9c97 100644 --- a/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt +++ b/review/src/main/kotlin/br/all/domain/model/review/SystematicStudy.kt @@ -1,6 +1,6 @@ package br.all.domain.model.review -import br.all.domain.model.user.ResearcherId +import br.all.domain.model.collaboration.CollaborationId import br.all.domain.shared.ddd.Entity import br.all.domain.shared.ddd.Notification import br.all.domain.shared.utils.exists @@ -10,8 +10,8 @@ class SystematicStudy( id: SystematicStudyId, title: String, description: String, - owner: ResearcherId, - collaborators: Set = emptySet(), + owner: CollaborationId, + collaborators: Set = emptySet(), ) : Entity(id) { private val _collaborators = collaborators.toMutableSet() @@ -42,19 +42,19 @@ class SystematicStudy( it.addError("Systematic Study description must not be blank!") } - fun addCollaborator(researcherId: ResearcherId) = _collaborators.add(researcherId) + fun addCollaborator(collaborationId: CollaborationId) = _collaborators.add(collaborationId) - fun changeOwner(researcherId: ResearcherId) { - _collaborators.add(researcherId) - owner = researcherId + fun changeOwner(collaborationId: CollaborationId) { + _collaborators.add(collaborationId) + owner = collaborationId } - fun removeCollaborator(researcherId: ResearcherId) { - check(researcherId != owner) { "Cannot remove the Systematic Study owner: $owner" } - exists(researcherId in _collaborators) { - "Cannot remove member that is not part of the collaboration: $researcherId" + fun removeCollaborator(collaborationId: CollaborationId) { + check(collaborationId != owner) { "Cannot remove the Systematic Study owner: $owner" } + exists(collaborationId in _collaborators) { + "Cannot remove member that is not part of the collaboration: $collaborationId" } - _collaborators.remove(researcherId) + _collaborators.remove(collaborationId) } override fun toString() = "SystematicStudy(reviewId=$id, title='$title', description='$description', owner=$owner," + From e4dc6b44a8593d0dd6ff0b6d7d77d3794ddea8f9 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:08:04 -0300 Subject: [PATCH 128/153] feat: implement mapper for collaboration entities and dtos --- .../repository/CollaborationMapper.kt | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt new file mode 100644 index 000000000..f81fcd274 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt @@ -0,0 +1,37 @@ +package br.all.application.collaboration.repository + +import br.all.domain.model.collaboration.* +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId + +fun Invite.toDto(): InviteDto = InviteDto( + id = this.id.value(), + systematicStudyId = this.systematicStudyId.value(), + userId = this.userId.value, + inviteDate = this.inviteDate, + expirationDate = this.expirationDate +) + +fun InviteDto.toDomain(): Invite = Invite( + id = this.id.toInviteId(), + systematicStudyId = this.systematicStudyId.toSystematicStudyId(), + userId = this.userId.toResearcherId(), + inviteDate = this.inviteDate, + expirationDate = this.expirationDate +) + +fun Collaboration.toDto(): CollaborationDto = CollaborationDto( + id = this.id.value(), + systematicStudyId = this.systematicStudyId.value(), + userId = this.userId.value, + status = this.status.name, + permissions = this.permissions.map { it.name }.toSet() +) + +fun CollaborationDto.toDomain(): Collaboration = Collaboration( + id = this.id.toCollaborationId(), + systematicStudyId = this.systematicStudyId.toSystematicStudyId(), + userId = this.userId.toResearcherId(), + status = CollaborationStatus.valueOf(this.status), + permissions = this.permissions.map { CollaborationPermission.valueOf(it) }.toSet() +) \ No newline at end of file From 52dc3bb39c31afda16c3d1a67fb3b8b91cd70c90 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Fri, 11 Apr 2025 20:08:21 -0300 Subject: [PATCH 129/153] feat: create and implement CreateInviteService --- .../create/CreateInvitePresenter.kt | 5 ++ .../create/CreateInviteService.kt | 18 +++++++ .../create/CreateInviteServiceImpl.kt | 51 +++++++++++++++++++ .../all/shared/error/ApiExceptionHandler.kt | 1 - 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt new file mode 100644 index 000000000..9c98ea82c --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt @@ -0,0 +1,5 @@ +package br.all.application.collaboration.create + +import br.all.application.shared.presenter.GenericPresenter + +interface CreateInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt new file mode 100644 index 000000000..425e83802 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteService.kt @@ -0,0 +1,18 @@ +package br.all.application.collaboration.create + +import java.util.* + +interface CreateInviteService { + fun createInvite(presenter: CreateInvitePresenter, request: RequestModel) + + data class RequestModel( + val systematicStudyId: UUID, + val userId: UUID, + val inviteeId: UUID, + val permissions: Set + ) + + data class ResponseModel( + val inviteId: UUID + ) +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt new file mode 100644 index 000000000..f6bbd258f --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -0,0 +1,51 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDto +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.Invite +import br.all.domain.model.collaboration.toInviteId +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId +import java.time.LocalDateTime +import java.util.* + +class CreateInviteServiceImpl( + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository +) : CreateInviteService +{ + override fun createInvite(presenter: CreateInvitePresenter, request: CreateInviteService.RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + + if(presenter.isDone()) return + + if(systematicStudy!!.collaborators.any { it.value() == request.inviteeId }) { + presenter.prepareFailView( + IllegalArgumentException("User who is already a collaborator may not be invited") + ) + } + + val inviteId = UUID.randomUUID() + val invite = Invite( + inviteId.toInviteId(), + request.systematicStudyId.toSystematicStudyId(), + request.userId.toResearcherId(), + LocalDateTime.now() + ) + + collaborationRepository.saveOrUpdateInvite(invite.toDto()) + + presenter.prepareSuccessView(CreateInviteService.ResponseModel(inviteId)) + } +} \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt index ee74206d8..5ff8d72cd 100644 --- a/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt +++ b/web/src/main/kotlin/br/all/shared/error/ApiExceptionHandler.kt @@ -1,6 +1,5 @@ package br.all.shared.error -import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler From da6fb691820f2738ebc990665105d107f4e451fd Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 22:16:08 -0300 Subject: [PATCH 130/153] feat: add permissions to invite --- .../collaboration/create/CreateInviteServiceImpl.kt | 4 +++- .../collaboration/repository/CollaborationMapper.kt | 4 +++- .../br/all/application/collaboration/repository/InviteDto.kt | 3 ++- .../main/kotlin/br/all/domain/model/collaboration/Invite.kt | 4 ++++ .../br/all/infrastructure/collaboration/InviteDocument.kt | 3 ++- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt index f6bbd258f..f72371ae0 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -6,6 +6,7 @@ import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.CollaborationPermission import br.all.domain.model.collaboration.Invite import br.all.domain.model.collaboration.toInviteId import br.all.domain.model.review.SystematicStudy @@ -41,7 +42,8 @@ class CreateInviteServiceImpl( inviteId.toInviteId(), request.systematicStudyId.toSystematicStudyId(), request.userId.toResearcherId(), - LocalDateTime.now() + request.permissions.map { CollaborationPermission.valueOf(it) }.toSet(), + inviteDate = LocalDateTime.now(), ) collaborationRepository.saveOrUpdateInvite(invite.toDto()) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt index f81fcd274..b7e2fc168 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationMapper.kt @@ -9,13 +9,15 @@ fun Invite.toDto(): InviteDto = InviteDto( systematicStudyId = this.systematicStudyId.value(), userId = this.userId.value, inviteDate = this.inviteDate, - expirationDate = this.expirationDate + expirationDate = this.expirationDate, + permissions = this.permissions.map { it.name }.toSet() ) fun InviteDto.toDomain(): Invite = Invite( id = this.id.toInviteId(), systematicStudyId = this.systematicStudyId.toSystematicStudyId(), userId = this.userId.toResearcherId(), + permissions = this.permissions.map { CollaborationPermission.valueOf(it) }.toSet(), inviteDate = this.inviteDate, expirationDate = this.expirationDate ) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt index 609610c03..2ebf7cc41 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/InviteDto.kt @@ -8,5 +8,6 @@ class InviteDto ( val systematicStudyId: UUID, val userId: UUID, val inviteDate: LocalDateTime, - val expirationDate: LocalDateTime + val expirationDate: LocalDateTime, + val permissions: Set ) \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt index 67d23d287..b2bb0983d 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/Invite.kt @@ -11,10 +11,14 @@ class Invite( id: InviteId, val systematicStudyId: SystematicStudyId, val userId: ResearcherId, + permissions: Set = emptySet(), val inviteDate: LocalDateTime, val expirationDate: LocalDateTime = inviteDate.plusDays(30) ) : Entity(id) { + private val _permissions = permissions.toMutableSet() + val permissions get() = _permissions + init { val notification = validate() require(notification.hasNoErrors()) { notification.message() } diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt index 086d2276f..3f5b2626e 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/InviteDocument.kt @@ -11,5 +11,6 @@ data class InviteDocument( val systematicStudyId: UUID, val userId: UUID, val inviteDate: LocalDateTime, - val expirationDate: LocalDateTime, + val expirationDate: LocalDateTime, + val permissions: Set = emptySet() ) From e4dcbbb1c26e89d13fd57ab57f694b57b97485de Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:10:31 -0300 Subject: [PATCH 131/153] feat: implement delete for invites --- .../repository/CollaborationRepository.kt | 2 ++ .../collaboration/CollaborationRepositoryImpl.kt | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt index 7896877dd..70b1dd4ed 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/repository/CollaborationRepository.kt @@ -8,4 +8,6 @@ interface CollaborationRepository { fun listAllCollaborationsBySystematicStudyId(id: UUID): List fun listAllInvitesBySystematicStudyId(id: UUID): List + + fun deleteInvite(id: UUID) } \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt index 664db2977..2fcf188d8 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -3,6 +3,7 @@ package br.all.infrastructure.collaboration import br.all.application.collaboration.repository.CollaborationDto import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.collaboration.repository.InviteDto +import java.time.LocalDateTime import java.util.* class CollaborationRepositoryImpl( @@ -38,8 +39,14 @@ class CollaborationRepositoryImpl( } override fun listAllInvitesBySystematicStudyId(id: UUID): List { - return innerInviteRepository.findAll().filter { it.systematicStudyId == id }.map { - InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate) + return innerInviteRepository.findAll() + .filter { it.systematicStudyId == id && it.expirationDate.isBefore(LocalDateTime.now()) } + .map { + InviteDto(it.id, it.systematicStudyId, it.userId, it.inviteDate, it.expirationDate, it.permissions) } } + + override fun deleteInvite(id: UUID) { + innerInviteRepository.deleteById(id) + } } \ No newline at end of file From aa3009d307d9adf4173e7f28dd23afd913dbc348 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:42:15 -0300 Subject: [PATCH 132/153] feat: implement accept invite service --- .../create/AcceptInvitePresenter.kt | 6 ++ .../create/AcceptInviteService.kt | 17 ++++++ .../create/AcceptInviteServiceImpl.kt | 58 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt create mode 100644 review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt new file mode 100644 index 000000000..96a88cf71 --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInvitePresenter.kt @@ -0,0 +1,6 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.create.AcceptInviteService.ResponseModel +import br.all.application.shared.presenter.GenericPresenter + +interface AcceptInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt new file mode 100644 index 000000000..d4d780f0d --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteService.kt @@ -0,0 +1,17 @@ +package br.all.application.collaboration.create + +import java.util.* + +interface AcceptInviteService { + fun acceptInvite(presenter: AcceptInvitePresenter, request: RequestModel) + + data class RequestModel( + val systematicStudyId: UUID, + val userId: UUID, + val inviteId: UUID, + ) + + data class ResponseModel( + val collaborationId: UUID + ) +} \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt new file mode 100644 index 000000000..50d981ceb --- /dev/null +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt @@ -0,0 +1,58 @@ +package br.all.application.collaboration.create + +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDto +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.review.repository.fromDto +import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.user.CredentialsService +import br.all.domain.model.collaboration.Collaboration +import br.all.domain.model.collaboration.CollaborationPermission +import br.all.domain.model.collaboration.toCollaborationId +import br.all.domain.model.review.SystematicStudy +import br.all.domain.model.review.toSystematicStudyId +import br.all.domain.model.user.toResearcherId +import java.util.UUID + +class AcceptInviteServiceImpl( + private val systematicStudyRepository: SystematicStudyRepository, + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository +) : AcceptInviteService { + override fun acceptInvite(presenter: AcceptInvitePresenter, request: AcceptInviteService.RequestModel) { + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + + presenter.prepareIfFailsPreconditions(user, systematicStudy) + + if(presenter.isDone()) return + + if(systematicStudy!!.collaborators.any { it.value() == request.userId }) { + presenter.prepareFailView( + IllegalArgumentException("User is already a collaborator") + ) + return + } + + val allInvites = collaborationRepository.listAllInvitesBySystematicStudyId(request.systematicStudyId) + val userInvite = allInvites.firstOrNull { it.userId == request.userId } + + if(userInvite == null) { + presenter.prepareFailView(IllegalArgumentException("User has not been invited")) + return + } + + val collaborationId = UUID.randomUUID() + val collaboration = Collaboration( + collaborationId.toCollaborationId(), + request.systematicStudyId.toSystematicStudyId(), + request.userId.toResearcherId(), + permissions = userInvite.permissions.map { CollaborationPermission.valueOf(it) }.toSet() + ) + + collaborationRepository.saveOrUpdateCollaboration(collaboration.toDto()) + presenter.prepareSuccessView(AcceptInviteService.ResponseModel(collaborationId)) + } +} \ No newline at end of file From f2f4b1a8a510194451f6596728992bd4f528f37f Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Apr 2025 23:42:38 -0300 Subject: [PATCH 133/153] feat: add check for user that has already been invited --- .../collaboration/create/CreateInvitePresenter.kt | 3 ++- .../collaboration/create/CreateInviteServiceImpl.kt | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt index 9c98ea82c..6863ee42d 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInvitePresenter.kt @@ -1,5 +1,6 @@ package br.all.application.collaboration.create +import br.all.application.collaboration.create.CreateInviteService.ResponseModel import br.all.application.shared.presenter.GenericPresenter -interface CreateInvitePresenter : GenericPresenter \ No newline at end of file +interface CreateInvitePresenter : GenericPresenter \ No newline at end of file diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt index f72371ae0..68ad8fd75 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -37,6 +37,13 @@ class CreateInviteServiceImpl( ) } + val allInvites = collaborationRepository.listAllInvitesBySystematicStudyId(request.systematicStudyId) + if(allInvites.any { it.userId == request.inviteeId }) { + presenter.prepareFailView( + IllegalArgumentException("User who is already invited may not be invited again") + ) + } + val inviteId = UUID.randomUUID() val invite = Invite( inviteId.toInviteId(), From 244a1609650a6f45a8596f65711e87a784b156f7 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:36 -0300 Subject: [PATCH 134/153] fix: remove incorrectly typed and unused variables from systematic study --- .../review/create/CreateSystematicStudyService.kt | 1 - .../application/review/repository/SystematicStudyMapper.kt | 7 ++++--- .../br/all/domain/model/collaboration/CollaborationId.kt | 2 +- web/src/main/kotlin/br/all/review/requests/PostRequest.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt index 1b3ec80e4..44388d8e3 100644 --- a/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt +++ b/review/src/main/kotlin/br/all/application/review/create/CreateSystematicStudyService.kt @@ -9,7 +9,6 @@ interface CreateSystematicStudyService { val userId: UUID, val title : String, val description : String, - val collaborators : Set, ) data class ResponseModel( diff --git a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt index 961dbc4e3..462508aa0 100644 --- a/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt +++ b/review/src/main/kotlin/br/all/application/review/repository/SystematicStudyMapper.kt @@ -1,6 +1,7 @@ package br.all.application.review.repository import br.all.application.review.create.CreateSystematicStudyService.RequestModel +import br.all.domain.model.collaboration.CollaborationId import br.all.domain.model.user.ResearcherId import br.all.domain.model.review.SystematicStudy import br.all.domain.model.review.SystematicStudyId @@ -18,15 +19,15 @@ fun SystematicStudy.Companion.fromRequestModel(id: UUID, requestModel: RequestMo SystematicStudyId(id), requestModel.title, requestModel.description, - ResearcherId(requestModel.userId), + CollaborationId(requestModel.userId), ) fun SystematicStudy.Companion.fromDto(dto: SystematicStudyDto) = SystematicStudy( SystematicStudyId(dto.id), dto.title, dto.description, - ResearcherId(dto.owner), + CollaborationId(dto.owner), dto.collaborators - .map { ResearcherId(it) } + .map { CollaborationId(it) } .toMutableSet(), ) diff --git a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt index 104134f9c..da15c73e1 100644 --- a/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt +++ b/review/src/main/kotlin/br/all/domain/model/collaboration/CollaborationId.kt @@ -5,7 +5,7 @@ import br.all.domain.shared.ddd.Notification import java.util.* @JvmInline -value class CollaborationId(private val value: UUID) : Identifier { +value class CollaborationId(val value: UUID) : Identifier { init { val notification = validate() require(notification.hasNoErrors()) { notification.message() } diff --git a/web/src/main/kotlin/br/all/review/requests/PostRequest.kt b/web/src/main/kotlin/br/all/review/requests/PostRequest.kt index b617549f6..9f66aca77 100644 --- a/web/src/main/kotlin/br/all/review/requests/PostRequest.kt +++ b/web/src/main/kotlin/br/all/review/requests/PostRequest.kt @@ -9,5 +9,5 @@ data class PostRequest( val collaborators: Set, ) { fun toCreateRequestModel(userId: UUID) = - RequestModel(userId, title, description, collaborators) + RequestModel(userId, title, description) } \ No newline at end of file From b43c58e828ab076ad998d170794e171574e20469 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:48 -0300 Subject: [PATCH 135/153] feat: implement RestfulAcceptInvitePresenter --- .../presenter/RestfulAcceptInvitePresenter.kt | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt diff --git a/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt new file mode 100644 index 000000000..a86487f50 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulAcceptInvitePresenter.kt @@ -0,0 +1,30 @@ +package br.all.collaboration.presenter + +import br.all.application.collaboration.create.AcceptInvitePresenter +import br.all.application.collaboration.create.AcceptInviteService +import br.all.application.collaboration.create.CreateInvitePresenter +import br.all.application.collaboration.create.CreateInviteService +import br.all.shared.error.createErrorResponseFrom +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.* + +class RestfulAcceptInvitePresenter : AcceptInvitePresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: AcceptInviteService.ResponseModel) { + responseEntity = ResponseEntity.status(HttpStatus.CREATED).body(ViewModel(response.collaborationId)) + } + + override fun prepareFailView(throwable: Throwable) { + responseEntity = createErrorResponseFrom(throwable) + } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val collaborationId: UUID, + ) : RepresentationModel() + +} \ No newline at end of file From 17f5254d824fbfdc31c4c1553d715d1051ea0962 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:23:54 -0300 Subject: [PATCH 136/153] feat: implement RestfulAcceptInvitePresenter --- .../presenter/RestfulCreateInvitePresenter.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt diff --git a/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt new file mode 100644 index 000000000..aac75f54b --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/presenter/RestfulCreateInvitePresenter.kt @@ -0,0 +1,28 @@ +package br.all.collaboration.presenter + +import br.all.application.collaboration.create.CreateInvitePresenter +import br.all.application.collaboration.create.CreateInviteService +import br.all.shared.error.createErrorResponseFrom +import org.springframework.hateoas.RepresentationModel +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import java.util.* + +class RestfulCreateInvitePresenter : CreateInvitePresenter { + var responseEntity: ResponseEntity<*>? = null + + override fun prepareSuccessView(response: CreateInviteService.ResponseModel) { + responseEntity = ResponseEntity.status(HttpStatus.CREATED).body(ViewModel(response.inviteId)) + } + + override fun prepareFailView(throwable: Throwable) { + responseEntity = createErrorResponseFrom(throwable) + } + + override fun isDone() = responseEntity != null + + private data class ViewModel( + val inviteId: UUID, + ) : RepresentationModel() + +} \ No newline at end of file From 1d59f8731f19fdc12a8f186db8be2145aa3446bf Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 19:31:20 -0300 Subject: [PATCH 137/153] feat: create beans for collaboration services --- .../CollaborationRepositoryImpl.kt | 2 ++ .../CollaborationServicesConfiguration.kt | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt diff --git a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt index 2fcf188d8..4f6152b38 100644 --- a/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt +++ b/review/src/main/kotlin/br/all/infrastructure/collaboration/CollaborationRepositoryImpl.kt @@ -3,9 +3,11 @@ package br.all.infrastructure.collaboration import br.all.application.collaboration.repository.CollaborationDto import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.collaboration.repository.InviteDto +import org.springframework.stereotype.Repository import java.time.LocalDateTime import java.util.* +@Repository class CollaborationRepositoryImpl( private val innerCollaborationRepository: MongoCollaborationRepository, private val innerInviteRepository: MongoInviteRepository diff --git a/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt new file mode 100644 index 000000000..6f1536a57 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationServicesConfiguration.kt @@ -0,0 +1,31 @@ +package br.all.collaboration.controller + +import br.all.application.collaboration.create.AcceptInviteServiceImpl +import br.all.application.collaboration.create.CreateInviteServiceImpl +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.review.repository.SystematicStudyRepository +import br.all.application.user.CredentialsService +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class CollaborationServicesConfiguration { + + @Bean + fun createInviteService( + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository + ) = CreateInviteServiceImpl( + systematicStudyRepository, credentialsService, collaborationRepository + ) + + @Bean + fun acceptInviteService( + systematicStudyRepository: SystematicStudyRepository, + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository + ) = AcceptInviteServiceImpl( + systematicStudyRepository, credentialsService, collaborationRepository + ) +} \ No newline at end of file From 96d93472267d188b6a082d30a35566dd41464653 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sun, 13 Apr 2025 22:05:10 -0300 Subject: [PATCH 138/153] feat: create endpoints for invites --- .../controller/CollaborationController.kt | 57 +++++++++++++++++++ .../requests/PostInviteRequest.kt | 8 +++ 2 files changed, 65 insertions(+) create mode 100644 web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt create mode 100644 web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt diff --git a/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt new file mode 100644 index 000000000..f171f0955 --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/controller/CollaborationController.kt @@ -0,0 +1,57 @@ +package br.all.collaboration.controller + +import br.all.application.collaboration.create.AcceptInviteService +import br.all.application.collaboration.create.CreateInviteService +import br.all.collaboration.presenter.RestfulAcceptInvitePresenter +import br.all.collaboration.presenter.RestfulCreateInvitePresenter +import br.all.collaboration.requests.PostInviteRequest +import br.all.security.service.AuthenticationInfoService +import io.swagger.v3.oas.annotations.Operation +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import java.util.* + +@RestController +@RequestMapping("/api/v1/systematic-study/{systematicStudy}") +class CollaborationController( + private val createInviteService: CreateInviteService, + private val acceptInviteService: AcceptInviteService, + private val authenticationInfoService: AuthenticationInfoService, + ) { + + @PostMapping("/invite") + @Operation(summary = "Invite an user in a systematic study") + fun createInvite( + @PathVariable systematicStudy: UUID, + @RequestBody postRequest: PostInviteRequest + ): ResponseEntity<*> { + val presenter = RestfulCreateInvitePresenter() + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = CreateInviteService.RequestModel( + systematicStudy, + userId, + postRequest.inviteeId, + postRequest.permissions.toSet() + ) + createInviteService.createInvite(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } + + @PostMapping("/invite/{inviteId}/accept") + @Operation(summary = "Invite an user in a systematic study") + fun acceptInvite( + @PathVariable systematicStudy: UUID, + @PathVariable inviteId: UUID + ): ResponseEntity<*> { + val presenter = RestfulAcceptInvitePresenter() + val userId = authenticationInfoService.getAuthenticatedUserId() + val request = AcceptInviteService.RequestModel( + systematicStudy, + userId, + inviteId + ) + acceptInviteService.acceptInvite(presenter, request) + return presenter.responseEntity ?: ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + } +} \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt b/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt new file mode 100644 index 000000000..ad12991af --- /dev/null +++ b/web/src/main/kotlin/br/all/collaboration/requests/PostInviteRequest.kt @@ -0,0 +1,8 @@ +package br.all.collaboration.requests + +import java.util.UUID + +data class PostInviteRequest( + val inviteeId: UUID, + val permissions: List +) From 0edd8774ff4734815ca405356583de100a7e5f61 Mon Sep 17 00:00:00 2001 From: gabrmanh Date: Sat, 12 Jul 2025 21:00:21 -0300 Subject: [PATCH 139/153] feat: add new collab implementation to precondition checker --- .../collaboration/create/AcceptInviteServiceImpl.kt | 4 ++-- .../collaboration/create/CreateInviteServiceImpl.kt | 6 +++++- .../shared/presenter/PreconditionCheckerNEW.kt | 9 +++++---- .../report/find/AuthorNetworkServiceImplTest.kt | 4 ++-- .../report/find/FindStudiesByStageServiceImplTest.kt | 4 ++-- .../report/find/IncludedStudiesAnswersServiceImplTest.kt | 4 ++-- .../report/find/StudiesFunnelServiceImplTest.kt | 4 ++-- .../controller/RiskOfBiasQuestionControllerTest.kt | 9 +++++++++ .../test/kotlin/br/all/review/shared/TestDataFactory.kt | 8 ++++++++ 9 files changed, 37 insertions(+), 15 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt index 50d981ceb..4f33ec805 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/AcceptInviteServiceImpl.kt @@ -4,7 +4,7 @@ import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.collaboration.repository.toDto import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto -import br.all.application.shared.presenter.prepareIfFailsPreconditions +import br.all.application.shared.presenter.prepareIfUnauthorized import br.all.application.user.CredentialsService import br.all.domain.model.collaboration.Collaboration import br.all.domain.model.collaboration.CollaborationPermission @@ -25,7 +25,7 @@ class AcceptInviteServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfUnauthorized(user) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt index 68ad8fd75..dc9b605e3 100644 --- a/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/collaboration/create/CreateInviteServiceImpl.kt @@ -1,6 +1,7 @@ package br.all.application.collaboration.create import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.collaboration.repository.toDto import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -26,8 +27,11 @@ class CreateInviteServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/shared/presenter/PreconditionCheckerNEW.kt b/review/src/main/kotlin/br/all/application/shared/presenter/PreconditionCheckerNEW.kt index 525ff2f66..c59cdf8a8 100644 --- a/review/src/main/kotlin/br/all/application/shared/presenter/PreconditionCheckerNEW.kt +++ b/review/src/main/kotlin/br/all/application/shared/presenter/PreconditionCheckerNEW.kt @@ -3,17 +3,18 @@ package br.all.application.shared.presenter import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.shared.exceptions.UnauthenticatedUserException import br.all.application.shared.exceptions.UnauthorizedUserException +import br.all.domain.model.collaboration.Collaboration import br.all.domain.model.user.Researcher import br.all.domain.model.user.Role import br.all.domain.model.user.Role.ADMIN import br.all.domain.model.user.Role.COLLABORATOR -import br.all.domain.model.review.SystematicStudy fun GenericPresenter<*>.prepareIfFailsPreconditions( user: Researcher?, - systematicStudy: SystematicStudy?, - allowedRoles: Set = setOf(COLLABORATOR) + systematicStudy: br.all.domain.model.review.SystematicStudy?, + allowedRoles: Set = setOf(COLLABORATOR), + collaborations: List? ) { this.prepareIfUnauthorized(user, allowedRoles) if (this.isDone()) return @@ -27,7 +28,7 @@ fun GenericPresenter<*>.prepareIfFailsPreconditions( if (allowedRoles.contains(ADMIN) && existingUser.roles.contains(ADMIN)) return - if (!systematicStudy.collaborators.contains(existingUser.id)) + if(collaborations == null || collaborations.none{ it.userId == user.id }) this.prepareFailView(UnauthorizedUserException("User of id $existingUser can not perform this action.")) } diff --git a/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt index 196b9cf6a..3e9329519 100644 --- a/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt @@ -163,7 +163,7 @@ class AuthorNetworkServiceImplTest { sut.findAuthors(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } @@ -183,7 +183,7 @@ class AuthorNetworkServiceImplTest { sut.findAuthors(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } diff --git a/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt index 3399013b5..f03a1f2f9 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt @@ -192,7 +192,7 @@ class FindStudiesByStageServiceImplTest { sut.findStudiesByStage(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } @@ -210,7 +210,7 @@ class FindStudiesByStageServiceImplTest { sut.findStudiesByStage(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } diff --git a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt index 8c52c2dd8..1d4bb9b5c 100644 --- a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt @@ -280,7 +280,7 @@ class IncludedStudiesAnswersServiceImplTest { sut.findAnswers(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertEquals(true, presenter.isDone()) @@ -317,7 +317,7 @@ class IncludedStudiesAnswersServiceImplTest { sut.findAnswers(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertEquals(true, presenter.isDone()) diff --git a/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt index 4bdc31f3a..30dfc5966 100644 --- a/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt @@ -191,7 +191,7 @@ class StudiesFunnelServiceImplTest { sut.studiesFunnel(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } @@ -211,7 +211,7 @@ class StudiesFunnelServiceImplTest { sut.studiesFunnel(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any()) + presenter.prepareIfFailsPreconditions(any(), any(),) } assertTrue { presenter.isDone() } } diff --git a/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt b/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt index 2ea33c5e5..36255a232 100644 --- a/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt +++ b/web/src/test/kotlin/br/all/question/controller/RiskOfBiasQuestionControllerTest.kt @@ -1,6 +1,7 @@ package br.all.question.controller import br.all.domain.model.question.QuestionContextEnum +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.question.MongoQuestionRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.question.utils.TestDataFactory @@ -26,6 +27,7 @@ import java.util.* class RiskOfBiasQuestionControllerTest( @Autowired val repository: MongoQuestionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, + @Autowired val collaborationRepository: MongoCollaborationRepository, @Autowired val mockMvc: MockMvc, @Autowired private val testHelperService: TestHelperService, ) { @@ -52,6 +54,13 @@ class RiskOfBiasQuestionControllerTest( owner = user.id, ) ) + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt b/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt index bf5ded6e2..0844021c1 100644 --- a/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt +++ b/web/src/test/kotlin/br/all/review/shared/TestDataFactory.kt @@ -1,5 +1,7 @@ package br.all.review.shared +import br.all.domain.model.review.SystematicStudyId +import br.all.infrastructure.collaboration.CollaborationDocument import br.all.infrastructure.review.SystematicStudyDocument import io.github.serpro69.kfaker.Faker import java.util.* @@ -18,6 +20,12 @@ class TestDataFactory { collaborators: MutableSet = mutableSetOf(), ) = SystematicStudyDocument(id, title, description, owner, collaborators.also { it.add(owner) }.toSet()) + fun createCollaborationDocument( + id: UUID = UUID.randomUUID(), + systematicStudyId: UUID = this.systematicStudyId, + researcherId : UUID = this.ownerId + ) = CollaborationDocument(id, systematicStudyId, researcherId, "ACTIVE", setOf("EDIT", "REVIEW_STUDIES", "VIEW")) + fun createValidPostRequest( title: String = faker.book.title(), description: String = faker.lorem.words(), From 61f7c6a8a12086c979863cc2b9932c202b437a17 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 02:48:04 -0300 Subject: [PATCH 140/153] refactor: add collaboration --- .../protocol/find/FindProtocolServiceImpl.kt | 12 +++++++--- .../find/GetProtocolStageServiceImpl.kt | 11 +++++++-- .../update/UpdateProtocolServiceImpl.kt | 15 ++++++++---- .../create/CreateQuestionServiceImpl.kt | 15 ++++++++---- .../question/find/FindQuestionServiceImpl.kt | 19 ++++++++++----- .../FindAllBySystematicStudyIdServiceImpl.kt | 14 +++++++---- .../find/FindProtocolServiceImplTest.kt | 6 +++++ .../protocol/util/TestDataFactory.kt | 3 +++ .../util/PreconditionCheckerMockingNew.kt | 23 ++++++++++++++++++- 9 files changed, 94 insertions(+), 24 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolServiceImpl.kt index 5f6e43889..d097c0bec 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/FindProtocolServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.protocol.find +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.find.FindProtocolService.RequestModel import br.all.application.protocol.find.FindProtocolService.ResponseModel import br.all.application.protocol.repository.ProtocolRepository @@ -14,16 +16,20 @@ class FindProtocolServiceImpl( private val protocolRepository: ProtocolRepository, private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ) : FindProtocolService { override fun findById(presenter: FindProtocolPresenter, request: RequestModel) { val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() + val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyId = request.systematicStudyId - val systematicStudyDto = systematicStudyRepository.findById(systematicStudyId) + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt index 22403c249..4468c77df 100644 --- a/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.protocol.find +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.user.CredentialsService @@ -22,14 +24,19 @@ class GetProtocolStageServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, - private val questionRepository: QuestionRepository + private val questionRepository: QuestionRepository, + private val collaborationRepository: CollaborationRepository, ) : GetProtocolStageService { override fun getStage(presenter: GetProtocolStagePresenter, request: RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val protocolDto = protocolRepository.findById(request.systematicStudyId) diff --git a/review/src/main/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImpl.kt b/review/src/main/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImpl.kt index 68f9bbf3d..3d18549a7 100644 --- a/review/src/main/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.protocol.update +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.repository.copyUpdates import br.all.application.protocol.repository.fromDto @@ -24,17 +26,22 @@ class UpdateProtocolServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, private val studyReviewRepository: StudyReviewRepository, - private val scoreCalculatorService: ScoreCalculatorService + private val scoreCalculatorService: ScoreCalculatorService, + private val collaborationRepository: CollaborationRepository ) : UpdateProtocolService { override fun update(presenter: UpdateProtocolPresenter, request: RequestModel) { val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() val systematicStudyId = request.systematicStudyId - val systematicStudyDto = systematicStudyRepository.findById(systematicStudyId) + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val dto = protocolRepository.findById(systematicStudyId) diff --git a/review/src/main/kotlin/br/all/application/question/create/CreateQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/question/create/CreateQuestionServiceImpl.kt index 657309808..913f58fbd 100644 --- a/review/src/main/kotlin/br/all/application/question/create/CreateQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/question/create/CreateQuestionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.question.create +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.create.CreateQuestionService.QuestionType.* import br.all.application.question.create.CreateQuestionService.RequestModel import br.all.application.question.create.CreateQuestionService.ResponseModel @@ -20,6 +22,7 @@ class CreateQuestionServiceImpl( private val questionRepository: QuestionRepository, private val uuidGeneratorService: UuidGeneratorService, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : CreateQuestionService { override fun create( @@ -27,11 +30,15 @@ class CreateQuestionServiceImpl( request: RequestModel ) { val systematicStudyId = request.systematicStudyId - val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() - val systematicStudyDto = systematicStudyRepository.findById(systematicStudyId) + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } + + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt index 5927f0b03..ea064d5ba 100644 --- a/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.question.find +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.find.FindQuestionService.* import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository @@ -13,20 +15,25 @@ import br.all.domain.model.review.SystematicStudy class FindQuestionServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val questionRepository: QuestionRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindQuestionService { override fun findOne(presenter: FindQuestionPresenter, request: RequestModel) { - val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() + val user = credentialsService.loadCredentials(request.userId)?.toUser() + + val questionId = request.questionId val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } - val questionId = QuestionId(request.questionId) - presenter.prepareIfFailsPreconditions(user, systematicStudy) + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } + + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return - val question = questionRepository.findById(request.systematicStudyId, questionId.value) + val question = questionRepository.findById(request.systematicStudyId, questionId) if (question === null) { val message = "There is no review of id ${request.systematicStudyId} or question of id ${request.questionId}." diff --git a/review/src/main/kotlin/br/all/application/question/findAll/FindAllBySystematicStudyIdServiceImpl.kt b/review/src/main/kotlin/br/all/application/question/findAll/FindAllBySystematicStudyIdServiceImpl.kt index 61c7b650a..d16c1efd9 100644 --- a/review/src/main/kotlin/br/all/application/question/findAll/FindAllBySystematicStudyIdServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/question/findAll/FindAllBySystematicStudyIdServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.question.findAll +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.findAll.FindAllBySystematicStudyIdService.* import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository @@ -12,16 +14,20 @@ import br.all.domain.model.review.SystematicStudy class FindAllBySystematicStudyIdServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val questionRepository: QuestionRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ) : FindAllBySystematicStudyIdService { override fun findAllBySystematicStudyId(presenter: FindAllBySystematicStudyIdPresenter, request: RequestModel) { - val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() + val user = credentialsService.loadCredentials(request.userId)?.toUser() + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val questions = questionRepository.findAllBySystematicStudyId( diff --git a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt index 5ee20dc0b..6c1ec63bf 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.protocol.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.util.TestDataFactory import br.all.application.review.repository.SystematicStudyRepository @@ -8,6 +9,7 @@ import br.all.application.shared.exceptions.UnauthenticatedUserException import br.all.application.shared.exceptions.UnauthorizedUserException import br.all.application.user.CredentialsService import br.all.application.util.PreconditionCheckerMockingNew +import br.all.infrastructure.collaboration.MongoCollaborationRepository import io.mockk.every import io.mockk.impl.annotations.InjectMockKs import io.mockk.impl.annotations.MockK @@ -29,6 +31,8 @@ class FindProtocolServiceImplTest { private lateinit var credentialsService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindProtocolPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository @InjectMockKs private lateinit var sut: FindProtocolServiceImpl @@ -42,8 +46,10 @@ class FindProtocolServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, factory.researcher, factory.systematicStudy, + factory.collaboration ) } diff --git a/review/src/test/kotlin/br/all/application/protocol/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/protocol/util/TestDataFactory.kt index 4e4ad0392..560d4c038 100644 --- a/review/src/test/kotlin/br/all/application/protocol/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/protocol/util/TestDataFactory.kt @@ -14,6 +14,7 @@ import br.all.application.protocol.update.UpdateProtocolService.ResponseModel as class TestDataFactory { val researcher: UUID = UUID.randomUUID() val systematicStudy: UUID = UUID.randomUUID() + val collaboration: UUID = UUID.randomUUID() private val faker = Faker() @@ -163,4 +164,6 @@ class TestDataFactory { operator fun component1() = researcher operator fun component2() = systematicStudy + + operator fun component3() = collaboration } diff --git a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt index ad4286309..71e46b910 100644 --- a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt +++ b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt @@ -1,5 +1,7 @@ package br.all.application.util +import br.all.application.collaboration.repository.CollaborationDto +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyDto import br.all.application.review.repository.SystematicStudyRepository @@ -19,8 +21,10 @@ class PreconditionCheckerMockingNew( private val presenter: GenericPresenter<*>, private val credentialsService: CredentialsService, private val systematicStudyRepository: SystematicStudyRepository, + private val collaborationRepository: CollaborationRepository, private val userId: UUID, private val systematicStudyId: UUID, + private val collaborationId: UUID, ) { private val faker = Faker() private val systematicStudy = generateSystematicStudy() @@ -30,7 +34,12 @@ class PreconditionCheckerMockingNew( mockkStatic(GenericPresenter<*>::prepareIfFailsPreconditions) every { credentialsService.loadCredentials(userId) } returns user every { systematicStudyRepository.findById(systematicStudyId) } returns systematicStudy - every { presenter.prepareIfFailsPreconditions(any(), any()) } returns Unit + every { presenter.prepareIfFailsPreconditions( + any(), + any(), + allowedRoles = any(), + collaborations = any() + ) } returns Unit every { presenter.isDone() } returns false } @@ -130,6 +139,18 @@ class PreconditionCheckerMockingNew( mutableSetOf(ownerId).also { it.addAll(collaborators) }, ) + private fun generateCollaborationDto( + id: UUID = collaborationId, + status: String = faker.rockBand.name(), + permissions: Set = emptySet() + ) = CollaborationDto( + id = id, + systematicStudyId = systematicStudyId, + userId = userId, + status = status, + permissions = permissions + ) + private fun generateUserDto( userId: UUID = this.userId, userName: String = faker.name.firstName(), From d8615d905b636e7239562706b6d4eda047e86586 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 02:51:01 -0300 Subject: [PATCH 141/153] refactor: add collaboration to question services --- .../update/services/UpdateQuestionServiceImpl.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImpl.kt index 4b3bcd8bf..dea918dad 100644 --- a/review/src/main/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.question.update.services +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.create.CreateQuestionService.QuestionType import br.all.application.question.repository.QuestionRepository import br.all.application.question.repository.toDto @@ -18,15 +20,19 @@ class UpdateQuestionServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val questionRepository: QuestionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ) : UpdateQuestionService { override fun update(presenter: UpdateQuestionPresenter, request: RequestModel) { val systematicStudyId = request.systematicStudyId val userId = request.userId - val user = credentialsService.loadCredentials(userId)?.toUser() + val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val type = request.questionType From 7012cd9d455d7f24b2fc03702e4d0c1a8a132937 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 02:55:52 -0300 Subject: [PATCH 142/153] refactor: add collaboration to report services --- .../report/find/service/AuthorNetworkServiceImpl.kt | 8 +++++++- .../report/find/service/ExportProtocolServiceImpl.kt | 8 +++++++- .../report/find/service/FindAnswerServiceImpl.kt | 8 +++++++- .../report/find/service/FindCriteriaServiceImpl.kt | 8 +++++++- .../report/find/service/FindKeywordsServiceImpl.kt | 8 +++++++- .../report/find/service/FindSourceServiceImpl.kt | 8 +++++++- .../report/find/service/FindStudiesByStageServiceImpl.kt | 8 +++++++- .../find/service/FindStudyReviewCriteriaServiceImpl.kt | 8 +++++++- .../find/service/IncludedStudiesAnswersServiceImpl.kt | 9 ++++++++- .../report/find/service/StudiesFunnelServiceImpl.kt | 8 +++++++- 10 files changed, 71 insertions(+), 10 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/report/find/service/AuthorNetworkServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/AuthorNetworkServiceImpl.kt index 1723231ca..54fc254d6 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/AuthorNetworkServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/AuthorNetworkServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.report.find.presenter.AuthorNetworkPresenter import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -14,14 +16,18 @@ class AuthorNetworkServiceImpl( private val credentialsService: CredentialsService, private val studyReviewRepository: StudyReviewRepository, private val systematicStudyRepository: SystematicStudyRepository, + private val collaborationRepository: CollaborationRepository, ): AuthorNetworkService { override fun findAuthors(presenter: AuthorNetworkPresenter, request: AuthorNetworkService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/ExportProtocolServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/ExportProtocolServiceImpl.kt index d6888a901..e13148214 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/ExportProtocolServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/ExportProtocolServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolDto import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.ExportProtocolPresenter @@ -17,14 +19,18 @@ class ExportProtocolServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val formatterFactoryService: FormatterFactoryService, private val protocolRepository: ProtocolRepository, + private val collaborationRepository: CollaborationRepository ): ExportProtocolService { override fun exportProtocol(presenter: ExportProtocolPresenter, request: ExportProtocolService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt index e177d36e9..bc58260fc 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.repository.QuestionRepository import br.all.application.report.find.presenter.FindAnswerPresenter import br.all.application.review.repository.SystematicStudyRepository @@ -16,14 +18,18 @@ class FindAnswerServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val systematicStudyRepository: SystematicStudyRepository, private val questionRepository: QuestionRepository, + private val collaborationRepository: CollaborationRepository ): FindAnswerService { override fun find(presenter: FindAnswerPresenter, request: FindAnswerService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) val question = questionRepository.findById(request.systematicStudyId, request.questionId) diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindCriteriaServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindCriteriaServiceImpl.kt index 30bdbc79a..cd683e378 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindCriteriaServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindCriteriaServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.FindCriteriaPresenter @@ -15,14 +17,18 @@ class FindCriteriaServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, private val studyReviewRepository: StudyReviewRepository, + private val collaborationRepository: CollaborationRepository ): FindCriteriaService { override fun findCriteria(presenter: FindCriteriaPresenter, request: FindCriteriaService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindKeywordsServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindKeywordsServiceImpl.kt index 6a7f5f8fc..7ba35a8b8 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindKeywordsServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindKeywordsServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.report.find.presenter.FindKeywordsPresenter import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -14,14 +16,18 @@ class FindKeywordsServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ): FindKeywordsService { override fun findKeywords(presenter: FindKeywordsPresenter, request: FindKeywordsService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindSourceServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindSourceServiceImpl.kt index 08743ea03..bafc408d8 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindSourceServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindSourceServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.FindSourcePresenter import br.all.application.review.repository.SystematicStudyRepository @@ -17,14 +19,18 @@ class FindSourceServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ): FindSourceService { override fun findSource(presenter: FindSourcePresenter, request: FindSourceService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindStudiesByStageServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindStudiesByStageServiceImpl.kt index 1f9d26b35..1c2cef16f 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindStudiesByStageServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindStudiesByStageServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.report.find.presenter.FindStudiesByStagePresenter import br.all.application.report.find.service.FindStudiesByStageService.StudyCollection import br.all.application.review.repository.SystematicStudyRepository @@ -16,14 +18,18 @@ class FindStudiesByStageServiceImpl( private val credentialsService: CredentialsService, private val studyReviewRepository: StudyReviewRepository, private val systematicStudyRepository: SystematicStudyRepository, + private val collaborationRepository: CollaborationRepository, ): FindStudiesByStageService { override fun findStudiesByStage(presenter: FindStudiesByStagePresenter, request: FindStudiesByStageService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return if (request.stage != "selection" && request.stage != "extraction") { diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt index f1b8bc5ac..1e106fab8 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindStudyReviewCriteriaServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository @@ -16,6 +18,7 @@ class FindStudyReviewCriteriaServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, private val protocolRepository: ProtocolRepository, + private val collaborationRepository: CollaborationRepository ): FindStudyReviewCriteriaService { override fun findCriteria( presenter: FindStudyReviewCriteriaPresenter, @@ -25,8 +28,11 @@ class FindStudyReviewCriteriaServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt index 6bf52cbb3..52bb3a545 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.repository.QuestionDto import br.all.application.question.repository.QuestionRepository import br.all.application.report.find.presenter.IncludedStudiesAnswersPresenter @@ -11,6 +13,7 @@ import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService import br.all.domain.model.question.QuestionContextEnum import br.all.domain.model.review.SystematicStudy +import org.springframework.boot.autoconfigure.security.SecurityProperties import java.util.* class IncludedStudiesAnswersServiceImpl( @@ -18,6 +21,7 @@ class IncludedStudiesAnswersServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, private val systematicStudyRepository: SystematicStudyRepository, + private val collaborationRepository: CollaborationRepository, ) : IncludedStudiesAnswersService { override fun findAnswers(presenter: IncludedStudiesAnswersPresenter, request: IncludedStudiesAnswersService.RequestModel) { @@ -25,8 +29,11 @@ class IncludedStudiesAnswersServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/report/find/service/StudiesFunnelServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/StudiesFunnelServiceImpl.kt index eae33c249..9719f1aaf 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/StudiesFunnelServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/StudiesFunnelServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.report.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.report.find.presenter.StudiesFunnelPresenter import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -15,14 +17,18 @@ class StudiesFunnelServiceImpl( private val credentialsService: CredentialsService, private val studyReviewRepository: StudyReviewRepository, private val systematicStudyRepository: SystematicStudyRepository, + private val collaborationRepository: CollaborationRepository ): StudiesFunnelService { override fun studiesFunnel(presenter: StudiesFunnelPresenter, request: StudiesFunnelService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val allStudies = studyReviewRepository.findAllFromReview(request.systematicStudyId) From 95cf61c36361809e7a37979a1a676af9a61cdc81 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 02:57:19 -0300 Subject: [PATCH 143/153] refactor: remove unused import directives --- .../br/all/application/question/find/FindQuestionServiceImpl.kt | 1 - .../all/application/report/find/service/FindAnswerServiceImpl.kt | 1 - .../report/find/service/IncludedStudiesAnswersServiceImpl.kt | 1 - .../all/application/protocol/find/FindProtocolServiceImplTest.kt | 1 - 4 files changed, 4 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt index ea064d5ba..ef9f2d191 100644 --- a/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/question/find/FindQuestionServiceImpl.kt @@ -9,7 +9,6 @@ import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.user.CredentialsService -import br.all.domain.model.question.QuestionId import br.all.domain.model.review.SystematicStudy class FindQuestionServiceImpl( diff --git a/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt index bc58260fc..a0b5b54b7 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/FindAnswerServiceImpl.kt @@ -11,7 +11,6 @@ import br.all.application.shared.presenter.prepareIfFailsPreconditions import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService import br.all.domain.model.review.SystematicStudy -import java.util.* class FindAnswerServiceImpl( private val credentialsService: CredentialsService, diff --git a/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt b/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt index 52bb3a545..da98fd269 100644 --- a/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/report/find/service/IncludedStudiesAnswersServiceImpl.kt @@ -13,7 +13,6 @@ import br.all.application.study.repository.StudyReviewRepository import br.all.application.user.CredentialsService import br.all.domain.model.question.QuestionContextEnum import br.all.domain.model.review.SystematicStudy -import org.springframework.boot.autoconfigure.security.SecurityProperties import java.util.* class IncludedStudiesAnswersServiceImpl( diff --git a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt index 6c1ec63bf..378f78244 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/FindProtocolServiceImplTest.kt @@ -9,7 +9,6 @@ import br.all.application.shared.exceptions.UnauthenticatedUserException import br.all.application.shared.exceptions.UnauthorizedUserException import br.all.application.user.CredentialsService import br.all.application.util.PreconditionCheckerMockingNew -import br.all.infrastructure.collaboration.MongoCollaborationRepository import io.mockk.every import io.mockk.impl.annotations.InjectMockKs import io.mockk.impl.annotations.MockK From 507b4803ed38fddc3788f84628a3b7f2c97ba991 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 03:07:57 -0300 Subject: [PATCH 144/153] refactor: add collaboration to search session services --- .../create/CreateSearchSessionServiceImpl.kt | 13 ++++++++++--- .../delete/DeleteSearchSessionServiceImpl.kt | 18 ++++++++++-------- ...FindAllSearchSessionsBySourceServiceImpl.kt | 8 +++++++- .../FindAllSearchSessionsServiceImpl.kt | 8 +++++++- .../service/FindSearchSessionServiceImpl.kt | 8 +++++++- .../update/PatchSearchSessionServiceImpl.kt | 12 +++++++++--- .../update/UpdateSearchSessionServiceImpl.kt | 8 +++++++- 7 files changed, 57 insertions(+), 18 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt index 2fe2d3e2a..88e741d69 100644 --- a/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/create/CreateSearchSessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.create +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -30,19 +32,24 @@ class CreateSearchSessionServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, private val scoreCalculatorService: ScoreCalculatorService, - private val reviewSimilarityService: ReviewSimilarityService + private val reviewSimilarityService: ReviewSimilarityService, + private val collaborationRepository: CollaborationRepository ) : CreateSearchSessionService { - override fun createSession( presenter: CreateSearchSessionPresenter, request: RequestModel, file: String ) { val user = credentialsService.loadCredentials(request.userId)?.toUser() + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } + + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt index 9e2c3bdca..82aa9878a 100644 --- a/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.delete +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.search.repository.SearchSessionRepository @@ -12,21 +14,21 @@ class DeleteSearchSessionServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ) : DeleteSearchSessionService { override fun delete( presenter: DeleteSearchSessionPresenter, request: DeleteSearchSessionService.RequestModel, ) { val user = credentialsService.loadCredentials(request.userId)?.toUser() - val systematicStudy = - systematicStudyRepository - .findById( - request.systematicStudyId, - )?.let { - SystematicStudy.fromDto(it) - } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) + val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } + + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsBySourceServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsBySourceServiceImpl.kt index 9ab05349a..726bd7340 100644 --- a/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsBySourceServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsBySourceServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.search.find.presenter.FindAllSearchSessionsBySourcePresenter @@ -14,6 +16,7 @@ class FindAllSearchSessionsBySourceServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ): FindAllSearchSessionsBySourceService{ override fun findAllSessionsBySource ( presenter: FindAllSearchSessionsBySourcePresenter, request: RequestModel @@ -22,8 +25,11 @@ class FindAllSearchSessionsBySourceServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsServiceImpl.kt index d93f414dd..ae92d546d 100644 --- a/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/find/service/FindAllSearchSessionsServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.search.find.presenter.FindAllSearchSessionsPresenter @@ -13,14 +15,18 @@ class FindAllSearchSessionsServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ): FindAllSearchSessionsService { override fun findAllSearchSessions (presenter: FindAllSearchSessionsPresenter, request: RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/find/service/FindSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/find/service/FindSearchSessionServiceImpl.kt index 0a2cc516d..bdd495b64 100644 --- a/review/src/main/kotlin/br/all/application/search/find/service/FindSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/find/service/FindSearchSessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.search.find.presenter.FindSearchSessionPresenter @@ -15,6 +17,7 @@ class FindSearchSessionServiceImpl ( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindSearchSessionService { override fun findOneSession(presenter: FindSearchSessionPresenter, request: RequestModel) { @@ -22,8 +25,11 @@ class FindSearchSessionServiceImpl ( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/update/PatchSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/update/PatchSearchSessionServiceImpl.kt index 6dab525e9..4ef63dc3a 100644 --- a/review/src/main/kotlin/br/all/application/search/update/PatchSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/update/PatchSearchSessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.update +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto @@ -29,20 +31,24 @@ class PatchSearchSessionServiceImpl ( private val converterFactoryService: ConverterFactoryService, private val protocolRepository: ProtocolRepository, private val scoreCalculatorService: ScoreCalculatorService, - private val reviewSimilarityService: ReviewSimilarityService + private val reviewSimilarityService: ReviewSimilarityService, + private val collaborationRepository: CollaborationRepository ) : PatchSearchSessionService { override fun patchSession( presenter: PatchSearchSessionPresenter, request: PatchSearchSessionService.RequestModel, file: String ) { + val searchSessionDto = searchSessionRepository.findById(request.sessionId) val user = credentialsService.loadCredentials(request.userId)?.toUser() - val searchSessionDto = searchSessionRepository.findById(request.sessionId) val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImpl.kt index cf95e9429..b5d25504b 100644 --- a/review/src/main/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.search.update +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.search.repository.SearchSessionRepository @@ -18,6 +20,7 @@ class UpdateSearchSessionServiceImpl ( private val systematicStudyRepository: SystematicStudyRepository, private val searchSessionRepository: SearchSessionRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : UpdateSearchSessionService { override fun updateSession(presenter: UpdateSearchSessionPresenter, request: RequestModel ) { @@ -25,8 +28,11 @@ class UpdateSearchSessionServiceImpl ( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return From 5fa473bd3ee9a93795104ed745ebd2ee99e96451 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 03:14:02 -0300 Subject: [PATCH 145/153] refactor: add collaboration to services --- .../study/create/CreateStudyReviewServiceImpl.kt | 10 ++++++++-- .../service/FindAllStudyReviewsByAuthorServiceImpl.kt | 10 ++++++++-- .../service/FindAllStudyReviewsBySessionServiceImpl.kt | 8 +++++++- .../service/FindAllStudyReviewsBySourceServiceImpl.kt | 8 +++++++- .../find/service/FindAllStudyReviewsServiceImpl.kt | 8 +++++++- .../study/find/service/FindStudyReviewServiceImpl.kt | 8 +++++++- .../study/update/implementation/AnswerQuestionImpl.kt | 8 +++++++- .../implementation/BatchAnswerQuestionServiceImpl.kt | 8 +++++++- .../implementation/MarkAsDuplicatedServiceImpl.kt | 8 +++++++- .../update/implementation/RemoveCriteriaServiceImpl.kt | 8 +++++++- .../UpdateStudyReviewExtractionService.kt | 8 +++++++- .../implementation/UpdateStudyReviewPriorityService.kt | 8 +++++++- .../UpdateStudyReviewSelectionService.kt | 8 +++++++- .../implementation/UpdateStudyReviewServiceImpl.kt | 8 +++++++- 14 files changed, 100 insertions(+), 16 deletions(-) diff --git a/review/src/main/kotlin/br/all/application/study/create/CreateStudyReviewServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/create/CreateStudyReviewServiceImpl.kt index 60efb59c5..e769c6f2d 100644 --- a/review/src/main/kotlin/br/all/application/study/create/CreateStudyReviewServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/create/CreateStudyReviewServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.create +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -17,7 +19,8 @@ class CreateStudyReviewServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, - private val idGenerator: IdGeneratorService + private val idGenerator: IdGeneratorService, + private val collaborationRepository: CollaborationRepository ) : CreateStudyReviewService { override fun createFromStudy(presenter: CreateStudyReviewPresenter, request: RequestModel) { @@ -25,8 +28,11 @@ class CreateStudyReviewServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsByAuthorServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsByAuthorServiceImpl.kt index 5c46a7556..7a87d5536 100644 --- a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsByAuthorServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsByAuthorServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -12,7 +14,8 @@ import br.all.domain.model.review.SystematicStudy class FindAllStudyReviewsByAuthorServiceImpl ( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, - private val credentialsService: CredentialsService + private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindAllStudyReviewsByAuthorService { override fun findAllByAuthor( presenter: FindAllStudyReviewsByAuthorPresenter, @@ -22,8 +25,11 @@ class FindAllStudyReviewsByAuthorServiceImpl ( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val allStudyReviews = studyReviewRepository.findAllFromReview(request.systematicStudyId) diff --git a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySessionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySessionServiceImpl.kt index afcc58670..76abd10e7 100644 --- a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySessionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySessionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -12,6 +14,7 @@ class FindAllStudyReviewsBySessionServiceImpl ( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindAllStudyReviewsBySessionService { override fun findAllBySearchSession( @@ -22,8 +25,11 @@ class FindAllStudyReviewsBySessionServiceImpl ( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySourceServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySourceServiceImpl.kt index 3c96a6eb3..1a86956c9 100644 --- a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySourceServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsBySourceServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -16,6 +18,7 @@ class FindAllStudyReviewsBySourceServiceImpl( private val studyReviewRepository: StudyReviewRepository, // private val protocolRepository: ProtocolRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindAllStudyReviewsBySourceService { override fun findAllFromSearchSession(presenter: FindAllStudyReviewsBySourcePresenter, request: RequestModel) { @@ -23,8 +26,11 @@ class FindAllStudyReviewsBySourceServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsServiceImpl.kt index 50c5cba90..c4e90bb2d 100644 --- a/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/find/service/FindAllStudyReviewsServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.presenter.prepareIfFailsPreconditions @@ -14,6 +16,7 @@ class FindAllStudyReviewsServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindAllStudyReviewsService { override fun findAllFromReview(presenter: FindAllStudyReviewsPresenter, request: RequestModel) { @@ -21,8 +24,11 @@ class FindAllStudyReviewsServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/find/service/FindStudyReviewServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/find/service/FindStudyReviewServiceImpl.kt index 187151e10..c84a26cd8 100644 --- a/review/src/main/kotlin/br/all/application/study/find/service/FindStudyReviewServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/find/service/FindStudyReviewServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.find.service +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -15,6 +17,7 @@ class FindStudyReviewServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : FindStudyReviewService { override fun findOne(presenter: FindStudyReviewPresenter, request: RequestModel) { @@ -22,8 +25,11 @@ class FindStudyReviewServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/AnswerQuestionImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/AnswerQuestionImpl.kt index 438ca0e0d..f1ce6ce42 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/AnswerQuestionImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/AnswerQuestionImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.repository.QuestionRepository import br.all.application.question.repository.fromDto import br.all.application.review.repository.SystematicStudyRepository @@ -21,6 +23,7 @@ class AnswerQuestionImpl ( private val questionRepository: QuestionRepository, private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ): AnswerQuestionService { override fun answerQuestion( presenter: AnswerQuestionPresenter, @@ -31,8 +34,11 @@ class AnswerQuestionImpl ( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt index 724075ecd..6a8f753eb 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/BatchAnswerQuestionServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.question.repository.QuestionRepository import br.all.application.question.repository.fromDto import br.all.application.review.repository.SystematicStudyRepository @@ -37,6 +39,7 @@ class BatchAnswerQuestionServiceImpl( private val questionRepository: QuestionRepository, private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ): BatchAnswerQuestionService { @Transactional @@ -49,8 +52,11 @@ class BatchAnswerQuestionServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val reviewDto = studyReviewRepository.findById(request.systematicStudyId, request.studyReviewId) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/MarkAsDuplicatedServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/MarkAsDuplicatedServiceImpl.kt index 41d573c99..bd30d294b 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/MarkAsDuplicatedServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/MarkAsDuplicatedServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -17,6 +19,7 @@ class MarkAsDuplicatedServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : MarkAsDuplicatedService { override fun markAsDuplicated( @@ -27,8 +30,11 @@ class MarkAsDuplicatedServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val referenceStudyDto = studyReviewRepository.findById(request.systematicStudyId, request.referenceStudyId) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt index 986bf2327..a31e31ac5 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/RemoveCriteriaServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -18,14 +20,18 @@ class RemoveCriteriaServiceImpl( private val studyReviewRepository: StudyReviewRepository, private val systematicStudyRepository: SystematicStudyRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ): RemoveCriteriaService { override fun removeCriteria(presenter: RemoveCriteriaPresenter, request: RemoveCriteriaService.RequestModel) { val user = credentialsService.loadCredentials(request.userId)?.toUser() val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return val studyReviewDto = studyReviewRepository.findById(request.systematicStudyId, request.studyId) diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewExtractionService.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewExtractionService.kt index b2299b59e..6a97fe409 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewExtractionService.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewExtractionService.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -20,6 +22,7 @@ class UpdateStudyReviewExtractionService( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : UpdateStudyReviewStatusService { override fun changeStatus(presenter: UpdateStudyReviewStatusPresenter, request: RequestModel) { @@ -27,8 +30,11 @@ class UpdateStudyReviewExtractionService( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if (presenter.isDone()) return for (studyId in request.studyReviewId) { diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewPriorityService.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewPriorityService.kt index f5178af4d..fb898cdfc 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewPriorityService.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewPriorityService.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -20,6 +22,7 @@ class UpdateStudyReviewPriorityService( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : UpdateStudyReviewStatusService { override fun changeStatus(presenter: UpdateStudyReviewStatusPresenter, request: RequestModel) { @@ -27,8 +30,11 @@ class UpdateStudyReviewPriorityService( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewSelectionService.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewSelectionService.kt index bbc5f4a5f..3de6b6eb9 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewSelectionService.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewSelectionService.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -20,6 +22,7 @@ class UpdateStudyReviewSelectionService( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository ) : UpdateStudyReviewStatusService { override fun changeStatus(presenter: UpdateStudyReviewStatusPresenter, request: RequestModel){ @@ -27,8 +30,11 @@ class UpdateStudyReviewSelectionService( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return diff --git a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewServiceImpl.kt b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewServiceImpl.kt index 475d1706b..d04507e11 100644 --- a/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewServiceImpl.kt +++ b/review/src/main/kotlin/br/all/application/study/update/implementation/UpdateStudyReviewServiceImpl.kt @@ -1,5 +1,7 @@ package br.all.application.study.update.implementation +import br.all.application.collaboration.repository.CollaborationRepository +import br.all.application.collaboration.repository.toDomain import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.repository.fromDto import br.all.application.shared.exceptions.EntityNotFoundException @@ -17,6 +19,7 @@ class UpdateStudyReviewServiceImpl( private val systematicStudyRepository: SystematicStudyRepository, private val studyReviewRepository: StudyReviewRepository, private val credentialsService: CredentialsService, + private val collaborationRepository: CollaborationRepository, ) : UpdateStudyReviewService { override fun updateFromStudy(presenter: UpdateStudyReviewPresenter, request: UpdateStudyReviewService.RequestModel) { @@ -24,8 +27,11 @@ class UpdateStudyReviewServiceImpl( val systematicStudyDto = systematicStudyRepository.findById(request.systematicStudyId) val systematicStudy = systematicStudyDto?.let { SystematicStudy.fromDto(it) } + val collaborations = collaborationRepository + .listAllCollaborationsBySystematicStudyId(request.systematicStudyId) + .map { it.toDomain() } - presenter.prepareIfFailsPreconditions(user, systematicStudy) + presenter.prepareIfFailsPreconditions(user, systematicStudy, collaborations = collaborations) if(presenter.isDone()) return From f4176491727d84bcc2732aa61df21974f95bbbcf Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 08:38:21 -0300 Subject: [PATCH 146/153] test: add collaboration module to test --- .../find/GetProtocolStageServiceImplTest.kt | 11 ++++++++++- .../update/UpdateProtocolServiceImplTest.kt | 7 ++++++- .../create/CreateQuestionServiceImplTest.kt | 12 +++++++++++- .../find/FindQuestionServiceImplTest.kt | 12 +++++++++++- .../services/UpdateQuestionServiceImplTest.kt | 8 +++++++- .../question/util/TestDataFactory.kt | 2 ++ .../report/find/AuthorNetworkServiceImplTest.kt | 12 +++++++++--- .../find/ExportProtocolServiceImplTest.kt | 8 +++++++- .../report/find/FindAnswerServiceImplTest.kt | 8 +++++++- .../report/find/FindCriteriaServiceImplTest.kt | 8 +++++++- .../report/find/FindKeywordsServiceImplTest.kt | 8 +++++++- .../report/find/FindSourceServiceImplTest.kt | 8 +++++++- .../find/FindStudiesByStageServiceImplTest.kt | 12 +++++++++--- .../IncludedStudiesAnswersServiceImplTest.kt | 17 +++++++++-------- .../report/find/StudiesFunnelServiceImplTest.kt | 12 +++++++++--- 15 files changed, 118 insertions(+), 27 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt index 37c359294..d7b1ad25e 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.protocol.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.util.TestDataFactory as ProtocolFactory import br.all.application.study.util.TestDataFactory as StudyReviewFactory @@ -27,6 +28,7 @@ import br.all.application.protocol.repository.PicocDto import br.all.application.question.repository.QuestionRepository import br.all.domain.model.question.QuestionContextEnum import io.mockk.verify +import org.springframework.boot.autoconfigure.security.SecurityProperties @Tag("UnitTest") @Tag("ServiceTest") @@ -51,6 +53,9 @@ class GetProtocolStageServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var presenter: GetProtocolStagePresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: GetProtocolStageServiceImpl @@ -61,6 +66,7 @@ class GetProtocolStageServiceImplTest { private lateinit var researcherId: UUID private lateinit var systematicStudyId: UUID + private lateinit var collaboration: UUID @BeforeEach fun setup() { @@ -70,13 +76,16 @@ class GetProtocolStageServiceImplTest { researcherId = protocolFactory.researcher systematicStudyId = protocolFactory.systematicStudy + collaboration = protocolFactory.collaboration precondition = PreconditionCheckerMockingNew( presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + collaboration ) precondition.makeEverythingWork() diff --git a/review/src/test/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImplTest.kt index b4ef5dc0e..7371ff32c 100644 --- a/review/src/test/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/update/UpdateProtocolServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.protocol.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.protocol.util.TestDataFactory import br.all.application.review.repository.SystematicStudyRepository @@ -35,6 +36,8 @@ class UpdateProtocolServiceImplTest { private lateinit var scoreCalculatorService: ScoreCalculatorService @MockK(relaxed = true) private lateinit var presenter: UpdateProtocolPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository @InjectMockKs private lateinit var sut: UpdateProtocolServiceImpl @@ -44,13 +47,15 @@ class UpdateProtocolServiceImplTest { @BeforeEach fun setUp() { factory = TestDataFactory() - val (researcher, systematicStudy) = factory + val (researcher, systematicStudy, collaboration) = factory preconditionCheckerMocking = PreconditionCheckerMockingNew( presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcher, systematicStudy, + collaboration ) } diff --git a/review/src/test/kotlin/br/all/application/question/create/CreateQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/question/create/CreateQuestionServiceImplTest.kt index c4b539262..93d1283e5 100644 --- a/review/src/test/kotlin/br/all/application/question/create/CreateQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/question/create/CreateQuestionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.question.create +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.create.CreateQuestionService.QuestionType import br.all.application.question.create.CreateQuestionService.QuestionType.* import br.all.application.question.create.CreateQuestionService.ResponseModel @@ -39,6 +40,9 @@ class CreateQuestionServiceImplTest { @MockK(relaxed = true) private lateinit var presenter: CreateQuestionPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: CreateQuestionServiceImpl @@ -49,7 +53,13 @@ class CreateQuestionServiceImplTest { fun setUp() { factory = TestDataFactory() preconditionCheckerMocking = PreconditionCheckerMockingNew( - presenter, credentialsService, systematicRepository, factory.researcher, factory.systematicStudy + presenter, + credentialsService, + systematicRepository, + collaborationRepository, + factory.researcher, + factory.systematicStudy, + factory.collaboration ) } diff --git a/review/src/test/kotlin/br/all/application/question/find/FindQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/question/find/FindQuestionServiceImplTest.kt index 3dc8cb0dd..e86dfcbdc 100644 --- a/review/src/test/kotlin/br/all/application/question/find/FindQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/question/find/FindQuestionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.question.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.create.CreateQuestionService.* import br.all.application.question.repository.QuestionRepository import br.all.application.question.util.TestDataFactory @@ -35,6 +36,9 @@ class FindQuestionServiceImplTest { @MockK(relaxed = true) private lateinit var presenter: FindQuestionPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: FindQuestionServiceImpl @@ -45,7 +49,13 @@ class FindQuestionServiceImplTest { fun setUp() { factory = TestDataFactory() preconditionCheckerMocking = PreconditionCheckerMockingNew( - presenter, credentialsService, systematicRepository, factory.researcher, factory.systematicStudy + presenter, + credentialsService, + systematicRepository, + collaborationRepository, + factory.researcher, + factory.systematicStudy, + factory.collaboration ) } diff --git a/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt index 17dd479eb..21959974f 100644 --- a/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.question.update.services +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.create.CreateQuestionService.* import br.all.application.question.create.CreateQuestionService.QuestionType.* import br.all.application.question.repository.QuestionRepository @@ -41,6 +42,9 @@ class UpdateQuestionServiceImplTest { @MockK(relaxed = true) private lateinit var presenter: UpdateQuestionPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: UpdateQuestionServiceImpl @@ -54,8 +58,10 @@ class UpdateQuestionServiceImplTest { presenter, credentialsService, systematicRepository, + collaborationRepository, factory.researcher, - factory.systematicStudy + factory.systematicStudy, + factory.collaboration ) } diff --git a/review/src/test/kotlin/br/all/application/question/util/TestDataFactory.kt b/review/src/test/kotlin/br/all/application/question/util/TestDataFactory.kt index f1bdb5c59..204585c92 100644 --- a/review/src/test/kotlin/br/all/application/question/util/TestDataFactory.kt +++ b/review/src/test/kotlin/br/all/application/question/util/TestDataFactory.kt @@ -15,6 +15,7 @@ class TestDataFactory { val question: UUID = UUID.randomUUID() val code: String = faker.lorem.words() val description: String = faker.lorem.words() + val collaboration: UUID = UUID.randomUUID() fun generateTextualDto( questionId: UUID = question, @@ -233,4 +234,5 @@ class TestDataFactory { operator fun component1() = researcher operator fun component2() = systematicStudy operator fun component3() = question + operator fun component4() = collaboration } diff --git a/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt index 3e9329519..95617ff0a 100644 --- a/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/AuthorNetworkServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.report.find.presenter.AuthorNetworkPresenter import br.all.application.report.find.service.AuthorNetworkService import br.all.application.report.find.service.AuthorNetworkService.Edge @@ -39,6 +40,9 @@ class AuthorNetworkServiceImplTest { @MockK lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs lateinit var sut: AuthorNetworkServiceImpl @@ -54,8 +58,10 @@ class AuthorNetworkServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } @@ -163,7 +169,7 @@ class AuthorNetworkServiceImplTest { sut.findAuthors(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } @@ -183,7 +189,7 @@ class AuthorNetworkServiceImplTest { sut.findAuthors(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } diff --git a/review/src/test/kotlin/br/all/application/report/find/ExportProtocolServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/ExportProtocolServiceImplTest.kt index 62bf4ae84..54d83f0ec 100644 --- a/review/src/test/kotlin/br/all/application/report/find/ExportProtocolServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/ExportProtocolServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.ExportProtocolPresenter import br.all.application.report.find.service.ExportProtocolService @@ -37,6 +38,9 @@ class ExportProtocolServiceImplTest { @MockK private lateinit var formatterFactoryService: FormatterFactoryService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxUnitFun = true) private lateinit var presenter: ExportProtocolPresenter @@ -60,8 +64,10 @@ class ExportProtocolServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + factory.collaboration ) precondition.makeEverythingWork() } diff --git a/review/src/test/kotlin/br/all/application/report/find/FindAnswerServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindAnswerServiceImplTest.kt index 51aacd7fa..257d5412c 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindAnswerServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindAnswerServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionRepository import br.all.application.report.find.presenter.FindAnswerPresenter import br.all.application.report.find.service.FindAnswerService @@ -43,6 +44,9 @@ class FindAnswerServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var presenter: FindAnswerPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: FindAnswerServiceImpl @@ -67,8 +71,10 @@ class FindAnswerServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } diff --git a/review/src/test/kotlin/br/all/application/report/find/FindCriteriaServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindCriteriaServiceImplTest.kt index 1e80d12f2..4ca1a8de0 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindCriteriaServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindCriteriaServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.CriterionDto import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.FindCriteriaPresenter @@ -42,6 +43,9 @@ class FindCriteriaServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var studyReviewRepository: StudyReviewRepository + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxUnitFun = true) private lateinit var presenter: FindCriteriaPresenter @@ -69,8 +73,10 @@ class FindCriteriaServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } diff --git a/review/src/test/kotlin/br/all/application/report/find/FindKeywordsServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindKeywordsServiceImplTest.kt index 9486dccad..b065bf70c 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindKeywordsServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindKeywordsServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.report.find.presenter.FindKeywordsPresenter import br.all.application.report.find.service.FindKeywordsService import br.all.application.report.find.service.FindKeywordsServiceImpl @@ -38,6 +39,9 @@ class FindKeywordsServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var presenter: FindKeywordsPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: FindKeywordsServiceImpl @@ -58,8 +62,10 @@ class FindKeywordsServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } diff --git a/review/src/test/kotlin/br/all/application/report/find/FindSourceServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindSourceServiceImplTest.kt index b94b3a270..e573f0d47 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindSourceServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindSourceServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.report.find.presenter.FindSourcePresenter import br.all.application.report.find.service.FindSourceService @@ -41,6 +42,9 @@ class FindSourceServiceImplTest { @MockK private lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxUnitFun = true) private lateinit var presenter: FindSourcePresenter @@ -66,8 +70,10 @@ class FindSourceServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() diff --git a/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt index f03a1f2f9..5fcece208 100644 --- a/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/FindStudiesByStageServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.report.find.presenter.FindStudiesByStagePresenter import br.all.application.report.find.service.FindStudiesByStageService.RequestModel import br.all.application.report.find.service.FindStudiesByStageService.ResponseModel @@ -38,6 +39,9 @@ class FindStudiesByStageServiceImplTest { @MockK(relaxUnitFun = true) lateinit var studyReviewRepository: StudyReviewRepository + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK lateinit var credentialsService: CredentialsService @@ -56,8 +60,10 @@ class FindStudiesByStageServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } @@ -192,7 +198,7 @@ class FindStudiesByStageServiceImplTest { sut.findStudiesByStage(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } @@ -210,7 +216,7 @@ class FindStudiesByStageServiceImplTest { sut.findStudiesByStage(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } diff --git a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt index 1d4bb9b5c..13cce6016 100644 --- a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionDto import br.all.application.question.repository.QuestionRepository import br.all.application.report.find.presenter.IncludedStudiesAnswersPresenter @@ -46,6 +47,9 @@ class IncludedStudiesAnswersServiceImplTest { @MockK lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs lateinit var sut: IncludedStudiesAnswersServiceImpl @@ -71,8 +75,10 @@ class IncludedStudiesAnswersServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() @@ -101,7 +107,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> listOf(question1) QuestionContextEnum.EXTRACTION -> listOf(question2) - else -> emptyList() } } @@ -146,7 +151,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> robQuestions QuestionContextEnum.EXTRACTION -> extractionQuestions - else -> emptyList() } } @@ -190,7 +194,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> robQuestions QuestionContextEnum.EXTRACTION -> extractionQuestions - else -> emptyList() } } @@ -224,7 +227,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> robQuestions QuestionContextEnum.EXTRACTION -> extractionQuestions - else -> emptyList() } } @@ -267,7 +269,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> robQuestions QuestionContextEnum.EXTRACTION -> extractionQuestions - else -> emptyList() } } @@ -280,7 +281,7 @@ class IncludedStudiesAnswersServiceImplTest { sut.findAnswers(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertEquals(true, presenter.isDone()) @@ -317,7 +318,7 @@ class IncludedStudiesAnswersServiceImplTest { sut.findAnswers(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertEquals(true, presenter.isDone()) diff --git a/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt index 30dfc5966..310899e8d 100644 --- a/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/StudiesFunnelServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.report.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.report.find.presenter.StudiesFunnelPresenter import br.all.application.report.find.service.StudiesFunnelService import br.all.application.report.find.service.StudiesFunnelServiceImpl @@ -39,6 +40,9 @@ class StudiesFunnelServiceImplTest { @MockK lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs lateinit var sut: StudiesFunnelServiceImpl @@ -54,8 +58,10 @@ class StudiesFunnelServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, researcherId, - systematicStudyId + systematicStudyId, + UUID.randomUUID() ) precondition.makeEverythingWork() } @@ -191,7 +197,7 @@ class StudiesFunnelServiceImplTest { sut.studiesFunnel(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } @@ -211,7 +217,7 @@ class StudiesFunnelServiceImplTest { sut.studiesFunnel(presenter, request) verify(exactly = 1) { - presenter.prepareIfFailsPreconditions(any(), any(),) + presenter.prepareIfFailsPreconditions(any(), any(), any(), any()) } assertTrue { presenter.isDone() } } From e26077bfe68829d0e5c6b75d1c09080b90720a43 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 08:42:08 -0300 Subject: [PATCH 147/153] refactor: remove unused import directives --- .../protocol/find/GetProtocolStageServiceImplTest.kt | 1 - .../update/services/UpdateQuestionServiceImplTest.kt | 6 ------ .../report/find/IncludedStudiesAnswersServiceImplTest.kt | 1 - 3 files changed, 8 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt index d7b1ad25e..4235266af 100644 --- a/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/protocol/find/GetProtocolStageServiceImplTest.kt @@ -28,7 +28,6 @@ import br.all.application.protocol.repository.PicocDto import br.all.application.question.repository.QuestionRepository import br.all.domain.model.question.QuestionContextEnum import io.mockk.verify -import org.springframework.boot.autoconfigure.security.SecurityProperties @Tag("UnitTest") @Tag("ServiceTest") diff --git a/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt index 21959974f..67df74bec 100644 --- a/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/question/update/services/UpdateQuestionServiceImplTest.kt @@ -6,11 +6,8 @@ import br.all.application.question.create.CreateQuestionService.QuestionType.* import br.all.application.question.repository.QuestionRepository import br.all.application.question.update.presenter.UpdateQuestionPresenter import br.all.application.question.util.TestDataFactory -import br.all.application.user.credentials.ResearcherCredentialsService import br.all.application.review.repository.SystematicStudyRepository -import br.all.application.search.repository.SearchSessionRepository import br.all.application.user.CredentialsService -import br.all.application.util.PreconditionCheckerMocking import br.all.application.util.PreconditionCheckerMockingNew import br.all.domain.services.UuidGeneratorService import io.mockk.every @@ -36,9 +33,6 @@ class UpdateQuestionServiceImplTest { @MockK private lateinit var credentialsService: CredentialsService - @MockK - private lateinit var uuidGeneratorService: UuidGeneratorService - @MockK(relaxed = true) private lateinit var presenter: UpdateQuestionPresenter diff --git a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt index 13cce6016..e15093165 100644 --- a/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/report/find/IncludedStudiesAnswersServiceImplTest.kt @@ -309,7 +309,6 @@ class IncludedStudiesAnswersServiceImplTest { when (secondArg()) { QuestionContextEnum.ROB -> listOf(question1) QuestionContextEnum.EXTRACTION -> listOf(question2) - else -> emptyList() } } From b13461982ff93ea14ebef329f9b6861c276a1851 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 09:01:02 -0300 Subject: [PATCH 148/153] refactor: use collaboration in tests --- .../CreateSystematicStudyServiceImplTest.kt | 5 ++++- .../FindAllSystematicStudiesServiceImplTest.kt | 6 ++++++ .../FindSystematicStudyServiceImplTest.kt | 6 ++++++ .../UpdateSystematicStudyServiceImplTest.kt | 6 ++++++ .../create/CreateSearchSessionServiceImplTest.kt | 10 +++++++++- .../delete/DeleteSearchSessionServiceImplTest.kt | 7 +++++++ ...indAllSearchSessionsBySourceServiceImplTest.kt | 13 +++++++++++-- .../find/FindAllSearchSessionsServiceImplTest.kt | 15 ++++++++++++--- .../find/FindSearchSessionServiceImplTest.kt | 13 +++++++++++-- .../update/UpdateSearchSessionServiceImplTest.kt | 8 ++++++++ .../create/CreateStudyReviewServiceImplTest.kt | 12 ++++++++++-- .../FindAllStudyReviewsBySourceServiceImplTest.kt | 9 ++++++++- .../find/FindAllStudyReviewsServiceImplTest.kt | 9 ++++++++- .../study/find/FindStudyReviewServiceImplTest.kt | 10 +++++++++- .../study/update/AnswerQuestionImplTest.kt | 8 +++++++- .../update/BatchAnswerQuestionServiceImplTest.kt | 11 +++++++++-- .../update/MarkAsDuplicatedServiceImplTest.kt | 8 +++++++- .../UpdateStudyReviewExtractionServiceTest.kt | 9 ++++++++- .../UpdateStudyReviewPriorityServiceTest.kt | 10 +++++++++- ...UpdateStudyReviewSelectionStatusServiceTest.kt | 9 ++++++++- .../update/UpdateStudyReviewServiceImplTest.kt | 10 +++++++++- .../util/PreconditionCheckerMockingNew.kt | 3 +++ 22 files changed, 175 insertions(+), 22 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt b/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt index 4e2f486bb..d37450856 100644 --- a/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/review/create/CreateSystematicStudyServiceImplTest.kt @@ -17,6 +17,7 @@ import io.mockk.verify import io.mockk.verifyOrder import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -47,8 +48,10 @@ class CreateSystematicStudyServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, factory.researcher, - factory.systematicStudy + factory.systematicStudy, + UUID.randomUUID(), ) every { collaborationRepository.saveOrUpdateCollaboration(any()) } returns Unit diff --git a/review/src/test/kotlin/br/all/application/review/find/services/FindAllSystematicStudiesServiceImplTest.kt b/review/src/test/kotlin/br/all/application/review/find/services/FindAllSystematicStudiesServiceImplTest.kt index e8a2e1098..d274582ef 100644 --- a/review/src/test/kotlin/br/all/application/review/find/services/FindAllSystematicStudiesServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/review/find/services/FindAllSystematicStudiesServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.review.find.services +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.find.presenter.FindAllSystematicStudyPresenter import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.util.TestDataFactory @@ -15,6 +16,7 @@ import io.mockk.verify import io.mockk.verifyOrder import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -26,6 +28,8 @@ class FindAllSystematicStudiesServiceImplTest { private lateinit var credentialsService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindAllSystematicStudyPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository @InjectMockKs private lateinit var sut: FindAllSystematicStudiesServiceImpl @@ -39,8 +43,10 @@ class FindAllSystematicStudiesServiceImplTest { presenter, credentialsService, repository, + collaborationRepository, factory.researcher, factory.systematicStudy, + UUID.randomUUID(), ) } diff --git a/review/src/test/kotlin/br/all/application/review/find/services/FindSystematicStudyServiceImplTest.kt b/review/src/test/kotlin/br/all/application/review/find/services/FindSystematicStudyServiceImplTest.kt index 794058420..9ec3ed37f 100644 --- a/review/src/test/kotlin/br/all/application/review/find/services/FindSystematicStudyServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/review/find/services/FindSystematicStudyServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.review.find.services +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.find.presenter.FindSystematicStudyPresenter import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.util.TestDataFactory @@ -16,6 +17,7 @@ import io.mockk.verify import io.mockk.verifyOrder import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -27,6 +29,8 @@ class FindSystematicStudyServiceImplTest { private lateinit var credentialsService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindSystematicStudyPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository @InjectMockKs private lateinit var sut: FindSystematicStudyServiceImpl @@ -40,8 +44,10 @@ class FindSystematicStudyServiceImplTest { presenter, credentialsService, repository, + collaborationRepository, factory.researcher, factory.systematicStudy, + UUID.randomUUID(), ) } diff --git a/review/src/test/kotlin/br/all/application/review/update/services/UpdateSystematicStudyServiceImplTest.kt b/review/src/test/kotlin/br/all/application/review/update/services/UpdateSystematicStudyServiceImplTest.kt index 186732f91..2f77f6ab0 100644 --- a/review/src/test/kotlin/br/all/application/review/update/services/UpdateSystematicStudyServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/review/update/services/UpdateSystematicStudyServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.review.update.services +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyDto import br.all.application.review.repository.SystematicStudyRepository import br.all.application.review.update.presenter.UpdateSystematicStudyPresenter @@ -17,6 +18,7 @@ import io.mockk.verify import io.mockk.verifyOrder import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -28,6 +30,8 @@ class UpdateSystematicStudyServiceImplTest { private lateinit var credentialsService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: UpdateSystematicStudyPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository @InjectMockKs private lateinit var sut: UpdateSystematicStudyServiceImpl @@ -41,8 +45,10 @@ class UpdateSystematicStudyServiceImplTest { presenter, credentialsService, repository, + collaborationRepository, factory.researcher, factory.systematicStudy, + UUID.randomUUID(), ) } diff --git a/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt index 42a8eec8a..e6b18ed3c 100644 --- a/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/create/CreateSearchSessionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.search.create +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.util.TestDataFactory @@ -24,6 +25,7 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID import kotlin.test.Test @Tag("UnitTest") @@ -58,6 +60,9 @@ class CreateSearchSessionServiceImplTest { @MockK private lateinit var reviewSimilarityService: ReviewSimilarityService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxed = true) private lateinit var presenter: CreateSearchSessionPresenter @@ -77,15 +82,18 @@ class CreateSearchSessionServiceImplTest { studyReviewRepository, credentialsService, scoreCalculatorService, - reviewSimilarityService + reviewSimilarityService, + collaborationRepository, ) testDataFactory = TestDataFactory() preconditionCheckerMocking = PreconditionCheckerMockingNew( presenter, credentialsService, systematicStudyRepository, + collaborationRepository, testDataFactory.userId, testDataFactory.systematicStudyId, + UUID.randomUUID() ) } diff --git a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt index 265f33150..4a839031c 100644 --- a/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/delete/DeleteSearchSessionServiceImplTest.kt @@ -2,6 +2,7 @@ package br.all.application.search.delete +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.repository.SearchSessionRepository import br.all.application.search.util.TestDataFactory @@ -19,6 +20,7 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @ExtendWith(MockKExtension::class) class DeleteSearchSessionServiceImplTest { @@ -34,6 +36,9 @@ class DeleteSearchSessionServiceImplTest { @MockK private lateinit var credentialService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: DeleteSearchSessionServiceImpl @@ -48,8 +53,10 @@ class DeleteSearchSessionServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.userId, factory.systematicStudyId, + UUID.randomUUID() ) } diff --git a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt index 3ed9029cf..380fd7b27 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsBySourceServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.search.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.find.presenter.FindAllSearchSessionsBySourcePresenter import br.all.application.search.find.service.FindAllSearchSessionsBySourceService @@ -20,6 +21,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -35,6 +37,9 @@ class FindAllSearchSessionsBySourceServiceImplTest { @MockK private lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxed = true) private lateinit var presenter: FindAllSearchSessionsBySourcePresenter @@ -49,8 +54,10 @@ class FindAllSearchSessionsBySourceServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, factory.userId, factory.systematicStudyId, + UUID.randomUUID() ) } @@ -62,7 +69,8 @@ class FindAllSearchSessionsBySourceServiceImplTest { sut = FindAllSearchSessionsBySourceServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository, ) run { preconditionCheckerMocking.makeEverythingWork() } } @@ -97,7 +105,8 @@ class FindAllSearchSessionsBySourceServiceImplTest { sut = FindAllSearchSessionsBySourceServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository, ) } @Test diff --git a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt index 2ebb67cba..fb67a5bfe 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindAllSearchSessionsServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.search.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.find.presenter.FindAllSearchSessionsPresenter import br.all.application.search.find.service.FindAllSearchSessionsServiceImpl @@ -19,6 +20,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -34,6 +36,9 @@ class FindAllSearchSessionsServiceImplTest { @MockK private lateinit var credentialService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxed = true) private lateinit var presenter: FindAllSearchSessionsPresenter @@ -48,8 +53,10 @@ class FindAllSearchSessionsServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.userId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) } @@ -61,7 +68,8 @@ class FindAllSearchSessionsServiceImplTest { sut = FindAllSearchSessionsServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialService + credentialService, + collaborationRepository, ) run { preconditionCheckerMocking.makeEverythingWork() } } @@ -92,7 +100,8 @@ class FindAllSearchSessionsServiceImplTest { sut = FindAllSearchSessionsServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialService + credentialService, + collaborationRepository, ) } @Test diff --git a/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt index fae5ee1dc..5ebadabb0 100644 --- a/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/find/FindSearchSessionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.search.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.find.presenter.FindSearchSessionPresenter import br.all.application.search.find.service.FindSearchSessionServiceImpl @@ -20,6 +21,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -34,6 +36,9 @@ class FindSearchSessionServiceImplTest { @MockK private lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxed = true) private lateinit var presenter: FindSearchSessionPresenter @@ -48,8 +53,10 @@ class FindSearchSessionServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, factory.userId, factory.systematicStudyId, + UUID.randomUUID() ) } @@ -61,7 +68,8 @@ class FindSearchSessionServiceImplTest { sut = FindSearchSessionServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository, ) run { preconditionCheckerMocking.makeEverythingWork() } } @@ -86,7 +94,8 @@ class FindSearchSessionServiceImplTest { sut = FindSearchSessionServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository, ) } diff --git a/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt index 217307515..81d3043cd 100644 --- a/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/search/update/UpdateSearchSessionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.search.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.repository.SearchSessionDto import br.all.application.search.repository.SearchSessionRepository @@ -19,6 +20,7 @@ import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -36,6 +38,10 @@ class UpdateSearchSessionServiceImplTest { @MockK(relaxed = true) private lateinit var presenter: UpdateSearchSessionPresenter + + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @InjectMockKs private lateinit var sut: UpdateSearchSessionServiceImpl @@ -49,8 +55,10 @@ class UpdateSearchSessionServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.userId, factory.systematicStudyId, + UUID.randomUUID() ) } diff --git a/review/src/test/kotlin/br/all/application/study/create/CreateStudyReviewServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/create/CreateStudyReviewServiceImplTest.kt index c4d2934f3..8690f0787 100644 --- a/review/src/test/kotlin/br/all/application/study/create/CreateStudyReviewServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/create/CreateStudyReviewServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.create +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository import br.all.application.study.util.TestDataFactory @@ -11,6 +12,8 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID + @Tag("UnitTest") @Tag("ServiceTest") @ExtendWith(MockKExtension::class) @@ -24,6 +27,8 @@ class CreateStudyReviewServiceImplTest { private lateinit var idGenerator: IdGeneratorService @MockK private lateinit var credentialService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository @MockK(relaxUnitFun = true) private lateinit var presenter: CreateStudyReviewPresenter @@ -39,14 +44,17 @@ class CreateStudyReviewServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = CreateStudyReviewServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, - idGenerator + idGenerator, + collaborationRepository, ) } diff --git a/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsBySourceServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsBySourceServiceImplTest.kt index 5bb7dda53..11a78a184 100644 --- a/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsBySourceServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsBySourceServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.find.presenter.FindAllStudyReviewsBySourcePresenter import br.all.application.study.find.service.FindAllStudyReviewsBySourceServiceImpl @@ -12,6 +13,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -26,6 +28,8 @@ class FindAllStudyReviewsBySourceServiceImplTest { private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindAllStudyReviewsBySourcePresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: FindAllStudyReviewsBySourceServiceImpl @@ -39,13 +43,16 @@ class FindAllStudyReviewsBySourceServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = FindAllStudyReviewsBySourceServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository, ) } diff --git a/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsServiceImplTest.kt index f5dcc08c1..97d8eda9c 100644 --- a/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/find/FindAllStudyReviewsServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.find.presenter.FindAllStudyReviewsPresenter import br.all.application.study.find.service.FindAllStudyReviewsServiceImpl @@ -12,6 +13,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID @Tag("UnitTest") @Tag("ServiceTest") @@ -26,6 +28,8 @@ class FindAllStudyReviewsServiceImplTest { private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindAllStudyReviewsPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: FindAllStudyReviewsServiceImpl @@ -39,13 +43,16 @@ class FindAllStudyReviewsServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = FindAllStudyReviewsServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository, ) } diff --git a/review/src/test/kotlin/br/all/application/study/find/FindStudyReviewServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/find/FindStudyReviewServiceImplTest.kt index 092eeaf82..25fa3b44d 100644 --- a/review/src/test/kotlin/br/all/application/study/find/FindStudyReviewServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/find/FindStudyReviewServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.find +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.find.presenter.FindStudyReviewPresenter import br.all.application.study.find.service.FindStudyReviewServiceImpl @@ -12,6 +13,8 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID + @Tag("UnitTest") @Tag("ServiceTest") @ExtendWith(MockKExtension::class) @@ -21,6 +24,8 @@ class FindStudyReviewServiceImplTest { @MockK private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: FindStudyReviewPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: FindStudyReviewServiceImpl @@ -34,13 +39,16 @@ class FindStudyReviewServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = FindStudyReviewServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository, ) } diff --git a/review/src/test/kotlin/br/all/application/study/update/AnswerQuestionImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/AnswerQuestionImplTest.kt index d1fb013eb..cda44c8df 100644 --- a/review/src/test/kotlin/br/all/application/study/update/AnswerQuestionImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/AnswerQuestionImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException @@ -27,6 +28,8 @@ class AnswerQuestionImplTest { @MockK private lateinit var questionRepository: QuestionRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: AnswerQuestionPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: AnswerQuestionService @@ -42,14 +45,17 @@ class AnswerQuestionImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = AnswerQuestionImpl( studyReviewRepository, questionRepository, systematicStudyRepository, credentialService, + collaborationRepository, ) questionId = UUID.randomUUID() } diff --git a/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt index 829b8f8b1..724c42018 100644 --- a/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/BatchAnswerQuestionServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.repository.StudyReviewRepository @@ -40,6 +41,9 @@ class BatchAnswerQuestionServiceImplTest { @MockK private lateinit var credentialsService: CredentialsService + @MockK + private lateinit var collaborationRepository: CollaborationRepository + @MockK(relaxed = true) private lateinit var presenter: BatchAnswerQuestionPresenter @@ -55,14 +59,17 @@ class BatchAnswerQuestionServiceImplTest { presenter, credentialsService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = BatchAnswerQuestionServiceImpl( studyReviewRepository, questionRepository, systematicStudyRepository, - credentialsService + credentialsService, + collaborationRepository, ) questionId = UUID.randomUUID() } diff --git a/review/src/test/kotlin/br/all/application/study/update/MarkAsDuplicatedServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/MarkAsDuplicatedServiceImplTest.kt index d37b59b97..76a21c603 100644 --- a/review/src/test/kotlin/br/all/application/study/update/MarkAsDuplicatedServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/MarkAsDuplicatedServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.study.repository.StudyReviewRepository @@ -24,6 +25,8 @@ class MarkAsDuplicatedServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: MarkAsDuplicatedPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: MarkAsDuplicatedServiceImpl @@ -37,13 +40,16 @@ class MarkAsDuplicatedServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = MarkAsDuplicatedServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository ) } diff --git a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewExtractionServiceTest.kt b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewExtractionServiceTest.kt index 5e46f3dd6..2585cfd5a 100644 --- a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewExtractionServiceTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewExtractionServiceTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.study.repository.StudyReviewRepository @@ -13,6 +14,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID import kotlin.test.assertFailsWith @Tag("UnitTest") @@ -24,6 +26,8 @@ class UpdateStudyReviewExtractionServiceTest { @MockK(relaxUnitFun = true) private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: UpdateStudyReviewStatusPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: UpdateStudyReviewExtractionService @@ -37,13 +41,16 @@ class UpdateStudyReviewExtractionServiceTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = UpdateStudyReviewExtractionService( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository ) } diff --git a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewPriorityServiceTest.kt b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewPriorityServiceTest.kt index 7941e8b93..b8e76cb77 100644 --- a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewPriorityServiceTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewPriorityServiceTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.study.repository.StudyReviewRepository @@ -13,6 +14,8 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID + @Tag("UnitTest") @Tag("ServiceTest") @ExtendWith(MockKExtension::class) @@ -22,6 +25,8 @@ class UpdateStudyReviewPriorityServiceTest { @MockK(relaxUnitFun = true) private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: UpdateStudyReviewStatusPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: UpdateStudyReviewPriorityService @@ -35,13 +40,16 @@ class UpdateStudyReviewPriorityServiceTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = UpdateStudyReviewPriorityService( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository ) } diff --git a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewSelectionStatusServiceTest.kt b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewSelectionStatusServiceTest.kt index d3aac10c1..b075c2fcf 100644 --- a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewSelectionStatusServiceTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewSelectionStatusServiceTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.study.repository.StudyReviewRepository @@ -13,6 +14,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID import kotlin.test.assertFailsWith @Tag("UnitTest") @@ -24,6 +26,8 @@ class UpdateStudyReviewSelectionStatusServiceTest { @MockK(relaxUnitFun = true) private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: UpdateStudyReviewStatusPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: UpdateStudyReviewSelectionService @@ -37,13 +41,16 @@ class UpdateStudyReviewSelectionStatusServiceTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = UpdateStudyReviewSelectionService( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository ) } diff --git a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewServiceImplTest.kt b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewServiceImplTest.kt index 1262712ae..cfb5b1588 100644 --- a/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewServiceImplTest.kt +++ b/review/src/test/kotlin/br/all/application/study/update/UpdateStudyReviewServiceImplTest.kt @@ -1,5 +1,6 @@ package br.all.application.study.update +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.shared.exceptions.EntityNotFoundException import br.all.application.study.repository.StudyReviewRepository @@ -13,6 +14,8 @@ import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import org.junit.jupiter.api.* import org.junit.jupiter.api.extension.ExtendWith +import java.util.UUID + @Tag("UnitTest") @Tag("ServiceTest") @ExtendWith(MockKExtension::class) @@ -22,6 +25,8 @@ class UpdateStudyReviewServiceImplTest { @MockK(relaxUnitFun = true) private lateinit var systematicStudyRepository: SystematicStudyRepository @MockK private lateinit var credentialService: CredentialsService @MockK(relaxed = true) private lateinit var presenter: UpdateStudyReviewPresenter + @MockK + private lateinit var collaborationRepository: CollaborationRepository private lateinit var sut: UpdateStudyReviewServiceImpl @@ -35,13 +40,16 @@ class UpdateStudyReviewServiceImplTest { presenter, credentialService, systematicStudyRepository, + collaborationRepository, factory.researcherId, - factory.systematicStudyId + factory.systematicStudyId, + UUID.randomUUID() ) sut = UpdateStudyReviewServiceImpl( systematicStudyRepository, studyReviewRepository, credentialService, + collaborationRepository ) } diff --git a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt index 71e46b910..1c28cf466 100644 --- a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt +++ b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt @@ -40,6 +40,9 @@ class PreconditionCheckerMockingNew( allowedRoles = any(), collaborations = any() ) } returns Unit + every { collaborationRepository. + listAllCollaborationsBySystematicStudyId(systematicStudyId) + } returns collaborationId every { presenter.isDone() } returns false } From ad996812912b89350bddbd521a6e76614fe61e35 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 10:07:58 -0300 Subject: [PATCH 149/153] feat: add stubs for collab repo --- .../util/PreconditionCheckerMockingNew.kt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt index 1c28cf466..1ca3c0967 100644 --- a/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt +++ b/review/src/test/kotlin/br/all/application/util/PreconditionCheckerMockingNew.kt @@ -28,6 +28,7 @@ class PreconditionCheckerMockingNew( ) { private val faker = Faker() private val systematicStudy = generateSystematicStudy() + private val collaboration = generateCollaborationDto() fun makeEverythingWork() { val user = generateUserDto() @@ -42,13 +43,16 @@ class PreconditionCheckerMockingNew( ) } returns Unit every { collaborationRepository. listAllCollaborationsBySystematicStudyId(systematicStudyId) - } returns collaborationId + } returns listOf(collaboration) every { presenter.isDone() } returns false } fun makeUserUnauthenticated() { every { credentialsService.loadCredentials(userId) } returns null every { systematicStudyRepository.findById(systematicStudyId) } returns systematicStudy + every { collaborationRepository. + listAllCollaborationsBySystematicStudyId(systematicStudyId) + } returns listOf(collaboration) every { presenter.isDone() } returns true } @@ -56,6 +60,9 @@ class PreconditionCheckerMockingNew( val user = generateUnauthorizedUserDto() every { credentialsService.loadCredentials(userId) } returns user every { systematicStudyRepository.findById(systematicStudyId) } returns systematicStudy + every { collaborationRepository. + listAllCollaborationsBySystematicStudyId(systematicStudyId) + } returns listOf(collaboration) every { presenter.isDone() } returns true } @@ -63,6 +70,9 @@ class PreconditionCheckerMockingNew( val user = generateUserDto() every { credentialsService.loadCredentials(userId) } returns user every { systematicStudyRepository.findById(systematicStudyId) } returns null + every { collaborationRepository. + listAllCollaborationsBySystematicStudyId(systematicStudyId) + } returns emptyList() every { presenter.isDone() } returns false andThen true } @@ -70,6 +80,9 @@ class PreconditionCheckerMockingNew( val user = generateUserDto() every { credentialsService.loadCredentials(userId) } returns user every { systematicStudyRepository.findById(systematicStudyId) } returns systematicStudy + every { collaborationRepository. + listAllCollaborationsBySystematicStudyId(systematicStudyId) + } returns listOf(collaboration) every { repository.findById(systematicStudyId, questionId) } returns null every { presenter.isDone() } returns false andThen false andThen true } @@ -144,8 +157,8 @@ class PreconditionCheckerMockingNew( private fun generateCollaborationDto( id: UUID = collaborationId, - status: String = faker.rockBand.name(), - permissions: Set = emptySet() + status: String = "ACTIVE", + permissions: Set = setOf("EDIT") ) = CollaborationDto( id = id, systematicStudyId = systematicStudyId, From 6a2c814bff9294a3b7bb45281696eb94e68fe162 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 10:08:24 -0300 Subject: [PATCH 150/153] refactor: add collab repo in configuration --- .../ProtocolServicesConfiguration.kt | 28 ++++++-- .../QuestionServicesConfiguration.kt | 20 ++++-- .../ReportControllerConfiguration.kt | 33 +++++++-- .../SearchSessionServicesConfiguration.kt | 38 +++++++---- .../StudyReviewServicesConfiguration.kt | 68 ++++++++++++------- 5 files changed, 131 insertions(+), 56 deletions(-) diff --git a/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt b/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt index 11efb480f..de05097c6 100644 --- a/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/protocol/controller/ProtocolServicesConfiguration.kt @@ -1,5 +1,6 @@ package br.all.protocol.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.find.FindProtocolServiceImpl import br.all.application.protocol.find.GetProtocolStageServiceImpl import br.all.application.protocol.repository.ProtocolRepository @@ -19,7 +20,8 @@ class ProtocolServicesConfiguration { protocolRepository: ProtocolRepository, systematicStudyRepository: SystematicStudyRepository, credentialsService: CredentialsService, - ) = FindProtocolServiceImpl(protocolRepository, systematicStudyRepository, credentialsService) + collaborationRepository: CollaborationRepository + ) = FindProtocolServiceImpl(protocolRepository, systematicStudyRepository, credentialsService, collaborationRepository) @Bean fun updateProtocolService( @@ -27,8 +29,16 @@ class ProtocolServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, credentialsService: CredentialsService, studyReviewRepository: StudyReviewRepository, - scoreCalculatorService: ScoreCalculatorService - ) = UpdateProtocolServiceImpl(protocolRepository, systematicStudyRepository, credentialsService, studyReviewRepository, scoreCalculatorService) + scoreCalculatorService: ScoreCalculatorService, + collaborationRepository: CollaborationRepository + ) = UpdateProtocolServiceImpl( + protocolRepository, + systematicStudyRepository, + credentialsService, + studyReviewRepository, + scoreCalculatorService, + collaborationRepository + ) @Bean fun getProtocolStageService( @@ -36,6 +46,14 @@ class ProtocolServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, - questionRepository: QuestionRepository - ) = GetProtocolStageServiceImpl(protocolRepository, systematicStudyRepository, studyReviewRepository, credentialsService, questionRepository) + questionRepository: QuestionRepository, + collaborationRepository: CollaborationRepository + ) = GetProtocolStageServiceImpl( + protocolRepository, + systematicStudyRepository, + studyReviewRepository, + credentialsService, + questionRepository, + collaborationRepository + ) } diff --git a/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt b/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt index 11e3dacd6..cf859d74b 100644 --- a/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt @@ -1,5 +1,6 @@ package br.all.question.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.create.CreateQuestionServiceImpl import br.all.application.question.find.FindQuestionServiceImpl import br.all.application.question.findAll.FindAllBySystematicStudyIdServiceImpl @@ -21,37 +22,42 @@ class QuestionServicesConfiguration { questionRepository: QuestionRepository, credentialsService: CredentialsService, idGenerator: UuidGeneratorService, + collaborationRepository: CollaborationRepository ) = CreateQuestionServiceImpl( systematicStudyRepository, questionRepository, idGenerator, - credentialsService + credentialsService, + collaborationRepository ) @Bean fun findQuestionService( systematicStudyRepository: SystematicStudyRepository, questionRepository: QuestionRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindQuestionServiceImpl( - systematicStudyRepository, questionRepository, credentialsService + systematicStudyRepository, questionRepository, credentialsService, collaborationRepository ) @Bean fun findAllBySystematicStudyIdService( systematicStudyRepository: SystematicStudyRepository, questionRepository: QuestionRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllBySystematicStudyIdServiceImpl( - systematicStudyRepository, questionRepository, credentialsService + systematicStudyRepository, questionRepository, credentialsService, collaborationRepository ) @Bean fun updateQuestionService( systematicStudyRepository: SystematicStudyRepository, questionRepository: QuestionRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateQuestionServiceImpl( - systematicStudyRepository, questionRepository, credentialsService + systematicStudyRepository, questionRepository, credentialsService, collaborationRepository ) } \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt b/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt index 2edc0fc1c..ff9bd1961 100644 --- a/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt +++ b/web/src/main/kotlin/br/all/report/controller/ReportControllerConfiguration.kt @@ -1,5 +1,6 @@ package br.all.report.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.question.repository.QuestionRepository import br.all.application.report.find.service.* @@ -35,11 +36,13 @@ class ReportControllerConfiguration { studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = IncludedStudiesAnswersServiceImpl( questionRepository, studyReviewRepository, credentialsService, systematicStudyRepository, + collaborationRepository ) @Bean @@ -47,12 +50,14 @@ class ReportControllerConfiguration { protocolRepository: ProtocolRepository, studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, - systematicStudyRepository: SystematicStudyRepository + systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = FindCriteriaServiceImpl( protocolRepository, systematicStudyRepository, credentialsService, studyReviewRepository, + collaborationRepository ) @Bean @@ -61,11 +66,13 @@ class ReportControllerConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindSourceServiceImpl( protocolRepository, systematicStudyRepository, studyReviewRepository, credentialsService, + collaborationRepository ) @Bean @@ -73,10 +80,12 @@ class ReportControllerConfiguration { credentialsService: CredentialsService, studyReviewRepository: StudyReviewRepository, systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = AuthorNetworkServiceImpl( credentialsService, studyReviewRepository, systematicStudyRepository, + collaborationRepository ) @Bean @@ -84,10 +93,12 @@ class ReportControllerConfiguration { credentialsService: CredentialsService, systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, + collaborationRepository: CollaborationRepository ) = FindKeywordsServiceImpl( systematicStudyRepository, studyReviewRepository, - credentialsService + credentialsService, + collaborationRepository ) @Bean @@ -96,11 +107,13 @@ class ReportControllerConfiguration { systematicStudyRepository: SystematicStudyRepository, formatterFactoryService: FormatterFactoryService, protocolRepository: ProtocolRepository, + collaborationRepository: CollaborationRepository ) = ExportProtocolServiceImpl( credentialsService, systematicStudyRepository, formatterFactoryService, - protocolRepository + protocolRepository, + collaborationRepository ) @Bean @@ -108,10 +121,12 @@ class ReportControllerConfiguration { credentialsService: CredentialsService, studyReviewRepository: StudyReviewRepository, systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = FindStudiesByStageServiceImpl( credentialsService, studyReviewRepository, systematicStudyRepository, + collaborationRepository ) @Bean @@ -119,10 +134,12 @@ class ReportControllerConfiguration { credentialsService: CredentialsService, studyReviewRepository: StudyReviewRepository, systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = StudiesFunnelServiceImpl( credentialsService, studyReviewRepository, systematicStudyRepository, + collaborationRepository ) @Bean @@ -130,12 +147,14 @@ class ReportControllerConfiguration { credentialsService: CredentialsService, studyReviewRepository: StudyReviewRepository, systematicStudyRepository: SystematicStudyRepository, - questionRepository: QuestionRepository + questionRepository: QuestionRepository, + collaborationRepository: CollaborationRepository ) = FindAnswerServiceImpl( credentialsService, studyReviewRepository, systematicStudyRepository, - questionRepository + questionRepository, + collaborationRepository ) @Bean @@ -144,10 +163,12 @@ class ReportControllerConfiguration { studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, protocolRepository: ProtocolRepository, + collaborationRepository: CollaborationRepository ) = FindStudyReviewCriteriaServiceImpl( systematicStudyRepository, studyReviewRepository, credentialsService, - protocolRepository + protocolRepository, + collaborationRepository ) } \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/search/controller/SearchSessionServicesConfiguration.kt b/web/src/main/kotlin/br/all/search/controller/SearchSessionServicesConfiguration.kt index 14412925a..9c482d214 100644 --- a/web/src/main/kotlin/br/all/search/controller/SearchSessionServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/search/controller/SearchSessionServicesConfiguration.kt @@ -1,5 +1,6 @@ package br.all.search.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.protocol.repository.ProtocolRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.search.create.CreateSearchSessionServiceImpl @@ -48,6 +49,7 @@ class SearchSessionServicesConfiguration { protocolRepository: ProtocolRepository, scoreCalculatorService: ScoreCalculatorService, reviewSimilarityService: ReviewSimilarityService, + collaborationRepository: CollaborationRepository ) = PatchSearchSessionServiceImpl( systematicStudyRepository, searchSessionRepository, @@ -56,7 +58,8 @@ class SearchSessionServicesConfiguration { converterFactoryService, protocolRepository, scoreCalculatorService, - reviewSimilarityService + reviewSimilarityService, + collaborationRepository ) @Bean @@ -69,7 +72,8 @@ class SearchSessionServicesConfiguration { studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, scoreCalculatorService: ScoreCalculatorService, - reviewSimilarityService: ReviewSimilarityService + reviewSimilarityService: ReviewSimilarityService, + collaborationRepository: CollaborationRepository ) = CreateSearchSessionServiceImpl( searchSessionRepository, systematicStudyRepository, @@ -79,56 +83,64 @@ class SearchSessionServicesConfiguration { studyReviewRepository, credentialsService, scoreCalculatorService, - reviewSimilarityService + reviewSimilarityService, + collaborationRepository ) @Bean fun findSearchSession( searchSessionRepository: SearchSessionRepository, systematicStudyRepository: SystematicStudyRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindSearchSessionServiceImpl ( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository ) @Bean fun findAllSessionService( searchSessionRepository: SearchSessionRepository, systematicStudyRepository: SystematicStudyRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllSearchSessionsServiceImpl ( - systematicStudyRepository, searchSessionRepository, credentialsService + systematicStudyRepository, searchSessionRepository, credentialsService, collaborationRepository ) @Bean fun findAllSearchSessionsBySourceService( searchSessionRepository: SearchSessionRepository, systematicStudyRepository: SystematicStudyRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllSearchSessionsBySourceServiceImpl ( - systematicStudyRepository, searchSessionRepository, credentialsService + systematicStudyRepository, searchSessionRepository, credentialsService, collaborationRepository ) @Bean fun updateSessionService( searchSessionRepository: SearchSessionRepository, systematicStudyRepository: SystematicStudyRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateSearchSessionServiceImpl ( - systematicStudyRepository, searchSessionRepository, credentialsService + systematicStudyRepository, searchSessionRepository, credentialsService, collaborationRepository ) @Bean fun deleteSearchSessionService( credentialsService: CredentialsService, searchSessionRepository: SearchSessionRepository, - systematicStudyRepository: SystematicStudyRepository + systematicStudyRepository: SystematicStudyRepository, + collaborationRepository: CollaborationRepository ) = DeleteSearchSessionServiceImpl( systematicStudyRepository, searchSessionRepository, - credentialsService + credentialsService, + collaborationRepository ) } \ No newline at end of file diff --git a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt index ea5d2acd6..42b5c6f66 100644 --- a/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/study/controller/StudyReviewServicesConfiguration.kt @@ -1,5 +1,6 @@ package br.all.study.controller +import br.all.application.collaboration.repository.CollaborationRepository import br.all.application.question.repository.QuestionRepository import br.all.application.review.repository.SystematicStudyRepository import br.all.application.study.create.CreateStudyReviewServiceImpl @@ -23,9 +24,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, - idGenerator: IdGeneratorService + idGenerator: IdGeneratorService, + collaborationRepository: CollaborationRepository ) = CreateStudyReviewServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService, idGenerator + systematicStudyRepository, studyReviewRepository, credentialsService, idGenerator, collaborationRepository ) @Bean @@ -33,8 +35,9 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateStudyReviewServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService, + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -42,9 +45,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, findAllStudyReviewsPresenter: FindAllStudyReviewsPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllStudyReviewsServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -53,36 +57,40 @@ class StudyReviewServicesConfiguration { studyReviewRepository: StudyReviewRepository, //protocolRepository: ProtocolRepository, findAllStudyReviewsBySourcePresenter: FindAllStudyReviewsBySourcePresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllStudyReviewsBySourceServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean fun findAllReviewBySessionService( systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllStudyReviewsBySessionServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean fun findReviewService( systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, findStudyReviewPresenter: FindStudyReviewPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindStudyReviewServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean fun findAllByAuthorService( systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = FindAllStudyReviewsByAuthorServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @@ -91,9 +99,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, updateStudyReviewStatusPresenter: UpdateStudyReviewStatusPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateStudyReviewSelectionService( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -101,9 +110,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, updateStudyReviewStatusPresenter: UpdateStudyReviewStatusPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateStudyReviewExtractionService( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -111,9 +121,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, updateStudyReviewStatusPresenter: UpdateStudyReviewStatusPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = UpdateStudyReviewPriorityService( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -121,9 +132,10 @@ class StudyReviewServicesConfiguration { systematicStudyRepository: SystematicStudyRepository, studyReviewRepository: StudyReviewRepository, updateStudyReviewStatusPresenter: UpdateStudyReviewStatusPresenter, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = MarkAsDuplicatedServiceImpl( - systematicStudyRepository, studyReviewRepository, credentialsService + systematicStudyRepository, studyReviewRepository, credentialsService, collaborationRepository ) @Bean @@ -132,11 +144,13 @@ class StudyReviewServicesConfiguration { questionRepository: QuestionRepository, systematicStudyRepository: SystematicStudyRepository, credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = AnswerQuestionImpl( studyReviewRepository, questionRepository, systematicStudyRepository, - credentialsService + credentialsService, + collaborationRepository ) @Bean @@ -144,12 +158,14 @@ class StudyReviewServicesConfiguration { studyReviewRepository: StudyReviewRepository, questionRepository: QuestionRepository, systematicStudyRepository: SystematicStudyRepository, - credentialsService: CredentialsService + credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = BatchAnswerQuestionServiceImpl( studyReviewRepository, questionRepository, systematicStudyRepository, - credentialsService + credentialsService, + collaborationRepository ) @Bean @@ -157,9 +173,11 @@ class StudyReviewServicesConfiguration { studyReviewRepository: StudyReviewRepository, systematicStudyRepository: SystematicStudyRepository, credentialsService: CredentialsService, + collaborationRepository: CollaborationRepository ) = RemoveCriteriaServiceImpl( studyReviewRepository, systematicStudyRepository, - credentialsService + credentialsService, + collaborationRepository ) } \ No newline at end of file From 0da9d8c154cab0ef8ff8f9b35cba73e2580b37b5 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 10:08:59 -0300 Subject: [PATCH 151/153] refactor: remove unused params --- .../br/all/question/controller/QuestionServicesConfiguration.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt b/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt index cf859d74b..067374cc6 100644 --- a/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt +++ b/web/src/main/kotlin/br/all/question/controller/QuestionServicesConfiguration.kt @@ -5,9 +5,7 @@ import br.all.application.question.create.CreateQuestionServiceImpl import br.all.application.question.find.FindQuestionServiceImpl import br.all.application.question.findAll.FindAllBySystematicStudyIdServiceImpl import br.all.application.question.repository.QuestionRepository -import br.all.application.question.update.presenter.UpdateQuestionPresenter import br.all.application.question.update.services.UpdateQuestionServiceImpl -import br.all.application.user.credentials.ResearcherCredentialsService import br.all.application.review.repository.SystematicStudyRepository import br.all.application.user.CredentialsService import br.all.domain.services.UuidGeneratorService From 4b39425d128ecdbd65dee16e97b145dbdf084891 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 10:18:42 -0300 Subject: [PATCH 152/153] test: add collaboration repo to web tests --- .../all/protocol/controller/ProtocolControllerTest.kt | 9 +++++++++ .../controller/ExtractionQuestionControllerTest.kt | 9 +++++++++ .../br/all/report/controller/ReportControllerTest.kt | 9 +++++++++ .../review/controller/SystematicStudyControllerTest.kt | 9 +++++++++ .../search/controller/SearchSessionControllerTest.kt | 10 ++++++++++ .../all/study/controller/StudyReviewControllerTest.kt | 10 ++++++++++ 6 files changed, 56 insertions(+) diff --git a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt index b99006f85..05770fe0e 100644 --- a/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt +++ b/web/src/test/kotlin/br/all/protocol/controller/ProtocolControllerTest.kt @@ -1,6 +1,7 @@ package br.all.protocol.controller import br.all.application.protocol.repository.CriterionDto +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.protocol.MongoProtocolRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.infrastructure.review.SystematicStudyDocument @@ -29,6 +30,7 @@ import br.all.review.shared.TestDataFactory as SystematicStudyTestDataFactory class ProtocolControllerTest( @Autowired private val protocolRepository: MongoProtocolRepository, @Autowired private val systematicStudyRepository: MongoSystematicStudyRepository, + @Autowired val collaborationRepository: MongoCollaborationRepository, @Autowired private val mockMvc: MockMvc, @Autowired private val testHelperService: TestHelperService ) { @@ -53,6 +55,13 @@ class ProtocolControllerTest( collaborators = mutableSetOf(user.id) ) systematicStudyRepository.save(systematicStudy) + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt b/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt index f9b441db8..677dec47a 100644 --- a/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt +++ b/web/src/test/kotlin/br/all/question/controller/ExtractionQuestionControllerTest.kt @@ -1,6 +1,7 @@ package br.all.question.controller import br.all.domain.model.question.QuestionContextEnum +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.question.MongoQuestionRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.question.utils.TestDataFactory @@ -26,6 +27,7 @@ import java.util.* class ExtractionQuestionControllerTest( @Autowired val repository: MongoQuestionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, + @Autowired val collaborationRepository: MongoCollaborationRepository, @Autowired val mockMvc: MockMvc, @Autowired private val testHelperService: TestHelperService, ) { @@ -49,6 +51,13 @@ class ExtractionQuestionControllerTest( id = systematicStudyId, owner = user.id, )) + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt index 8c3cb88c4..ca1004642 100644 --- a/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt +++ b/web/src/test/kotlin/br/all/report/controller/ReportControllerTest.kt @@ -1,6 +1,7 @@ package br.all.report.controller import br.all.domain.model.question.QuestionContextEnum +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.protocol.MongoProtocolRepository import br.all.infrastructure.question.MongoQuestionRepository import br.all.infrastructure.question.QuestionDocument @@ -37,6 +38,7 @@ class ReportControllerTest( @Autowired private val systematicStudyRepository: MongoSystematicStudyRepository, @Autowired private val questionRepository: MongoQuestionRepository, @Autowired private val protocolRepository: MongoProtocolRepository, + @Autowired private val collaborationRepository: MongoCollaborationRepository, @Autowired private val mockMvc: MockMvc, @Autowired private val testHelperService: TestHelperService ) { @@ -84,6 +86,13 @@ class ReportControllerTest( studyReviewRepository.save(studyReview) systematicStudyRepository.save(systematicStudy) + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudy.id, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt index 43224dc85..36f40b6dc 100644 --- a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt +++ b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt @@ -1,5 +1,6 @@ package br.all.review.controller +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.infrastructure.shared.toNullable import br.all.review.shared.TestDataFactory @@ -26,6 +27,7 @@ import java.util.* @Tag("ControllerTest") class SystematicStudyControllerTest( @Autowired private val repository: MongoSystematicStudyRepository, + @Autowired private val collaborationRepository: MongoCollaborationRepository, @Autowired private val testHelperService: TestHelperService, @Autowired private val mockMvc: MockMvc, ) { @@ -37,6 +39,13 @@ class SystematicStudyControllerTest( repository.deleteAll() factory = TestDataFactory() user = testHelperService.createApplicationUser() + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = factory.systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt index 1d3fe1a22..2e897741b 100644 --- a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt +++ b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt @@ -1,5 +1,6 @@ package br.all.search.controller +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.protocol.MongoProtocolRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.infrastructure.search.MongoSearchSessionRepository @@ -35,6 +36,7 @@ class SearchSessionControllerTest( @Autowired val repository: MongoSearchSessionRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, @Autowired val studyReviewRepository: MongoStudyReviewRepository, + @Autowired val collaborationRepository: MongoCollaborationRepository, @Autowired val protocolRepository: MongoProtocolRepository, @Autowired val idService: StudyReviewIdGeneratorService, @Autowired private val testHelperService: TestHelperService, @@ -73,6 +75,14 @@ class SearchSessionControllerTest( owner = user.id, ) ) + + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach diff --git a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt index 7a2233ff9..452194717 100644 --- a/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt +++ b/web/src/test/kotlin/br/all/study/controller/StudyReviewControllerTest.kt @@ -1,5 +1,6 @@ package br.all.study.controller +import br.all.infrastructure.collaboration.MongoCollaborationRepository import br.all.infrastructure.question.MongoQuestionRepository import br.all.infrastructure.review.MongoSystematicStudyRepository import br.all.infrastructure.shared.toNullable @@ -36,6 +37,7 @@ import br.all.review.shared.TestDataFactory as SystematicStudyTestDataFactory class StudyReviewControllerTest( @Autowired val repository: MongoStudyReviewRepository, @Autowired val systematicStudyRepository: MongoSystematicStudyRepository, + @Autowired val collaborationRepository: MongoCollaborationRepository, @Autowired private val testHelperService: TestHelperService, @Autowired val idService: StudyReviewIdGeneratorService, @Autowired val mockMvc: MockMvc, @@ -99,6 +101,14 @@ class StudyReviewControllerTest( owner = user.id, ) ) + + collaborationRepository.deleteAll() + collaborationRepository.save( + br.all.review.shared.TestDataFactory().createCollaborationDocument( + systematicStudyId = systematicStudyId, + researcherId = user.id + ) + ) } @AfterEach From edebb5b2c7f952f7f206f3ca6106958a4faa4719 Mon Sep 17 00:00:00 2001 From: ericksgmes Date: Mon, 28 Jul 2025 10:20:24 -0300 Subject: [PATCH 153/153] test: remove unused code --- .../br/all/review/controller/SystematicStudyControllerTest.kt | 2 +- .../br/all/search/controller/SearchSessionControllerTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt index 36f40b6dc..d2bb7e090 100644 --- a/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt +++ b/web/src/test/kotlin/br/all/review/controller/SystematicStudyControllerTest.kt @@ -41,7 +41,7 @@ class SystematicStudyControllerTest( user = testHelperService.createApplicationUser() collaborationRepository.deleteAll() collaborationRepository.save( - br.all.review.shared.TestDataFactory().createCollaborationDocument( + TestDataFactory().createCollaborationDocument( systematicStudyId = factory.systematicStudyId, researcherId = user.id ) diff --git a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt index 2e897741b..a36572077 100644 --- a/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt +++ b/web/src/test/kotlin/br/all/search/controller/SearchSessionControllerTest.kt @@ -50,7 +50,7 @@ class SearchSessionControllerTest( fun postUrl() = "/api/v1/systematic-study/$systematicStudyId/search-session" - fun patchUrl(sessionId: UUID) = "/api/v1/systematic-study/$systematicStudyId/patch-search-session/${sessionId}" + // fun patchUrl(sessionId: UUID) = "/api/v1/systematic-study/$systematicStudyId/patch-search-session/${sessionId}" fun findUrl(sessionId: UUID) = "/api/v1/systematic-study/$systematicStudyId/search-session/${sessionId}" fun findAllUrl() = "/api/v1/systematic-study/$systematicStudyId/search-session"