diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/reporting/changes/repository/SyncRepository.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/reporting/changes/repository/SyncRepository.kt index e8906e3..e3ce92d 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/reporting/changes/repository/SyncRepository.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/reporting/changes/repository/SyncRepository.kt @@ -9,7 +9,7 @@ import org.springframework.data.repository.CrudRepository import org.springframework.stereotype.Repository import java.util.* -@Entity +@Entity(name = "couchdb_sync_entry") data class SyncEntry( @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SqlSearchUserProfileUseCase.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SqlSearchUserProfileUseCase.kt index a13ede9..bf44360 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SqlSearchUserProfileUseCase.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/core/SqlSearchUserProfileUseCase.kt @@ -8,17 +8,47 @@ import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileEnti import com.aamdigital.aambackendservice.skill.repository.SkillLabUserProfileRepository import org.springframework.data.domain.Example import org.springframework.data.domain.ExampleMatcher +import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable +/** + * Search for an SkillLabUserProfile with provides information from SearchUserProfileRequest + * + * 1. search for exact email matches + * 2. search for mobile phone matches + * 3. search for name + * + * The first exact match will be returned. Otherwise, a list of possible matches is returned + * + */ class SqlSearchUserProfileUseCase( private val userProfileRepository: SkillLabUserProfileRepository, ) : SearchUserProfileUseCase() { - override fun apply(request: SearchUserProfileRequest): UseCaseOutcome { - val matcher = ExampleMatcher.matchingAll() + companion object { + private const val MAX_RESULTS = 10; + + private val MATCHER_EMAIL = ExampleMatcher.matchingAny() + .withIgnorePaths( + "id", + "externalIdentifier", + "fullName", + "mobileNumber", + "skills", + "updatedAt", + "latestSyncAt", + "importedAt", + ) + .withIgnoreCase() + .withIncludeNullValues() + .withStringMatcher(ExampleMatcher.StringMatcher.EXACT) + + private val MATCHER_PHONE = ExampleMatcher.matchingAny() .withIgnorePaths( "id", "externalIdentifier", + "fullName", + "email", "skills", "updatedAt", "latestSyncAt", @@ -28,6 +58,24 @@ class SqlSearchUserProfileUseCase( .withIncludeNullValues() .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) + private val MATCHER_NAME = ExampleMatcher.matchingAll() + .withIgnorePaths( + "id", + "externalIdentifier", + "mobileNumber", + "email", + "skills", + "updatedAt", + "latestSyncAt", + "importedAt", + ) + .withIgnoreCase() + .withIncludeNullValues() + .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) + } + + override fun apply(request: SearchUserProfileRequest): UseCaseOutcome { + val userProfile = SkillLabUserProfileEntity( id = 0, externalIdentifier = "", @@ -40,38 +88,75 @@ class SqlSearchUserProfileUseCase( importedAt = null, ) - val example = Example.of(userProfile, matcher) + var searchResults: Page; - val searchResults = userProfileRepository.findAll(example, Pageable.ofSize(10)) + // check for exact matches for email + if (!userProfile.email.isNullOrBlank()) { + searchResults = userProfileRepository.findAll( + Example.of(userProfile, MATCHER_EMAIL), Pageable.ofSize(MAX_RESULTS) + ) - if (searchResults.isEmpty) { - return UseCaseOutcome.Success( - data = SearchUserProfileData( - result = emptyList(), + if (!searchResults.isEmpty) { + return UseCaseOutcome.Success( + data = SearchUserProfileData( + result = searchResults.toList().map { + toDto(it) + } + ) ) + } + } + + // check for matches for phone + if (!userProfile.mobileNumber.isNullOrBlank()) { + searchResults = userProfileRepository.findAll( + Example.of(userProfile, MATCHER_PHONE), Pageable.ofSize(MAX_RESULTS) ) + + if (!searchResults.isEmpty) { + return UseCaseOutcome.Success( + data = SearchUserProfileData( + result = searchResults.toList().map { + toDto(it) + } + ) + ) + } + } + + // check for name + searchResults = if (!userProfile.fullName.isNullOrBlank()) { + userProfileRepository.findAll( + Example.of(userProfile, MATCHER_NAME), Pageable.ofSize(MAX_RESULTS) + ) + } else { + Page.empty() } return UseCaseOutcome.Success( data = SearchUserProfileData( result = searchResults.toList().map { - UserProfile( - id = it.externalIdentifier, - fullName = it.fullName, - email = it.email, - phone = it.mobileNumber, - skills = it.skills.map { skill -> - EscoSkill( - usage = SkillUsage.valueOf(skill.usage.uppercase()), - escoUri = skill.escoUri - ) - }, - latestSyncAt = it.latestSyncAt?.toInstant(), - importedAt = it.importedAt?.toInstant(), - updatedAtExternalSystem = it.updatedAt - ) + toDto(it) } ) ) } + + private fun toDto(it: SkillLabUserProfileEntity): UserProfile { + return UserProfile( + id = it.externalIdentifier, + fullName = it.fullName, + email = it.email, + phone = it.mobileNumber, + skills = it.skills.map { skill -> + EscoSkill( + usage = SkillUsage.valueOf(skill.usage.uppercase()), + escoUri = skill.escoUri + ) + }, + latestSyncAt = it.latestSyncAt?.toInstant(), + importedAt = it.importedAt?.toInstant(), + updatedAtExternalSystem = it.updatedAt + ) + } } diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt index 4e40259..6e65dd1 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/di/SkillConfiguration.kt @@ -32,9 +32,10 @@ import org.springframework.web.client.RestClient havingValue = "true", matchIfMissing = false ) -class AamRenderApiClientConfiguration( +class SkillLabApiClientConfiguration( val basePath: String, val apiKey: String, + val projectId: String, val responseTimeoutInSeconds: Int = 30, ) @@ -49,7 +50,7 @@ class SkillConfiguration { matchIfMissing = false ) fun skillLabApiClient( - configuration: AamRenderApiClientConfiguration + configuration: SkillLabApiClientConfiguration ): RestClient { val clientBuilder = RestClient.builder().baseUrl(configuration.basePath) diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt index f89b3a4..afd57e1 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/job/SyncSkillsJob.kt @@ -2,13 +2,15 @@ package com.aamdigital.aambackendservice.skill.job import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesRequest import com.aamdigital.aambackendservice.skill.core.FetchUserProfileUpdatesUseCase +import com.aamdigital.aambackendservice.skill.di.SkillLabApiClientConfiguration import org.slf4j.LoggerFactory import org.springframework.context.annotation.Configuration import org.springframework.scheduling.annotation.Scheduled @Configuration class SyncSkillsJob( - private val skillLabFetchUserProfileUpdatesUseCase: FetchUserProfileUpdatesUseCase + private val skillLabFetchUserProfileUpdatesUseCase: FetchUserProfileUpdatesUseCase, + private val skillLabApiClientConfiguration: SkillLabApiClientConfiguration, ) { private val logger = LoggerFactory.getLogger(javaClass) @@ -18,7 +20,7 @@ class SyncSkillsJob( private var MAX_ERROR_COUNT: Int = 5 } - @Scheduled(fixedDelay = (60000 * 10)) + @Scheduled(fixedDelay = (60000 * 10)) // every 10 minutes fun checkForCouchDbChanges() { if (ERROR_COUNTER >= MAX_ERROR_COUNT) { logger.trace("${this.javaClass.name}: MAX_ERROR_COUNT reached. Not starting job again.") @@ -28,7 +30,7 @@ class SyncSkillsJob( try { skillLabFetchUserProfileUpdatesUseCase.run( request = FetchUserProfileUpdatesRequest( - projectId = "343" + projectId = skillLabApiClientConfiguration.projectId ) ) } catch (ex: Exception) { diff --git a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt index 4d136f8..6b7efa7 100644 --- a/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt +++ b/application/aam-backend-service/src/main/kotlin/com/aamdigital/aambackendservice/skill/skilllab/SkillLabSyncUserProfileUseCase.kt @@ -44,7 +44,10 @@ class SkillLabSyncUserProfileUseCase( result = UserProfile( id = userProfileEntity.externalIdentifier, fullName = userProfileEntity.fullName, - phone = userProfileEntity.mobileNumber, + phone = userProfileEntity.mobileNumber + ?.replace(" ", "") + ?.replace("-", "") + ?.trim(), email = userProfileEntity.email, skills = allSkillsEntities.map { skill -> EscoSkill( diff --git a/application/aam-backend-service/src/main/resources/application.yaml b/application/aam-backend-service/src/main/resources/application.yaml index 162af28..1bd430c 100644 --- a/application/aam-backend-service/src/main/resources/application.yaml +++ b/application/aam-backend-service/src/main/resources/application.yaml @@ -110,6 +110,7 @@ sqs-client-configuration: skilllab-api-client-configuration: enabled: true api-key: skilllab-api-key + project-id: dummy-project base-path: http://localhost:9005/skilllab response-timeout-in-seconds: 15 diff --git a/application/aam-backend-service/src/test/resources/application-e2e.yaml b/application/aam-backend-service/src/test/resources/application-e2e.yaml index 34ca476..5b4f75a 100644 --- a/application/aam-backend-service/src/test/resources/application-e2e.yaml +++ b/application/aam-backend-service/src/test/resources/application-e2e.yaml @@ -66,6 +66,7 @@ sqs-client-configuration: skilllab-api-client-configuration: enabled: false api-key: skilllab-api-key + project-id: dummy-project base-path: http://localhost:9005/skilllab # todo test container response-timeout-in-seconds: 15