Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@
<dependency>
<groupId>io.mockk</groupId>
<artifactId>mockk</artifactId>
<version>1.12.4</version>
<version>1.11.0</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
4 changes: 3 additions & 1 deletion api/src/main/kotlin/edu/wgu/osmt/RoutePaths.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package edu.wgu.osmt

object RoutePaths {
const val SEARCH_PATH = "/api/search"
const val API = "/api"
const val SEARCH_PATH = "$API/search"
const val SEARCH_SKILLS = "$SEARCH_PATH/skills"
const val EXPORT_LIBRARY = "$API/export/library"
const val SEARCH_SIMILAR_SKILLS = "$SEARCH_SKILLS/similarity"
const val SEARCH_SIMILARITIES = "$SEARCH_SKILLS/similarities"
const val SEARCH_COLLECTIONS = "$SEARCH_PATH/collections"
Expand Down
24 changes: 24 additions & 0 deletions api/src/main/kotlin/edu/wgu/osmt/collection/CsvTaskProcessor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import edu.wgu.osmt.config.AppConfig
import edu.wgu.osmt.richskill.RichSkillAndCollections
import edu.wgu.osmt.richskill.RichSkillCsvExport
import edu.wgu.osmt.richskill.RichSkillDescriptorDao
import edu.wgu.osmt.richskill.RichSkillRepository
import edu.wgu.osmt.task.CsvTask
import edu.wgu.osmt.task.TaskMessageService
import edu.wgu.osmt.task.TaskStatus
Expand All @@ -28,6 +29,9 @@ class CsvTaskProcessor {
@Autowired
lateinit var collectionRepository: CollectionRepository

@Autowired
lateinit var richSkillRepository: RichSkillRepository

@Autowired
lateinit var appConfig: AppConfig

Expand All @@ -52,4 +56,24 @@ class CsvTaskProcessor {
logger.info("Task ${csvTask.uuid} completed")
}

@RqueueListener(
value = [TaskMessageService.skillsForFullLibraryCsv],
deadLetterQueueListenerEnabled = "true",
deadLetterQueue = TaskMessageService.deadLetters,
concurrency = "1"
)
fun csvSkillsInFullLibraryProcessor(csvTask: CsvTask) {
logger.info("Started processing task for Full Library export")

val csv = richSkillRepository.findAll()
?.with(RichSkillDescriptorDao::collections)
?.map { RichSkillAndCollections.fromDao(it) }
?.let { RichSkillCsvExport(appConfig).toCsv(it) }

taskMessageService.publishResult(
csvTask.copy(result = csv, status = TaskStatus.Ready)
)
logger.info("Full Library export task completed")
}

}
44 changes: 40 additions & 4 deletions api/src/main/kotlin/edu/wgu/osmt/richskill/RichSkillController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,31 @@ import edu.wgu.osmt.config.AppConfig
import edu.wgu.osmt.db.PublishStatus
import edu.wgu.osmt.elasticsearch.OffsetPageable
import edu.wgu.osmt.keyword.KeywordDao
import edu.wgu.osmt.security.*
import edu.wgu.osmt.task.*
import edu.wgu.osmt.security.OAuthHelper
import edu.wgu.osmt.task.AppliesToType
import edu.wgu.osmt.task.CreateSkillsTask
import edu.wgu.osmt.task.CsvTask
import edu.wgu.osmt.task.PublishTask
import edu.wgu.osmt.task.Task
import edu.wgu.osmt.task.TaskMessageService
import edu.wgu.osmt.task.TaskResult
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.*
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Controller
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.bind.annotation.*
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.server.ResponseStatusException
import org.springframework.web.util.UriComponentsBuilder

Expand Down Expand Up @@ -176,11 +192,31 @@ class RichSkillController @Autowired constructor(
fun skillAuditLog(
@PathVariable uuid: String
): HttpEntity<List<AuditLog>> {

val pageable = OffsetPageable(0, Int.MAX_VALUE, AuditLogSortEnum.forValueOrDefault(AuditLogSortEnum.DateDesc.apiValue).sort)

val skill = richSkillRepository.findByUUID(uuid)

val sizedIterable = auditLogRepository.findByTableAndId(RichSkillDescriptorTable.tableName, entityId = skill!!.id.value, offsetPageable = pageable)
return ResponseEntity.status(200).body(sizedIterable.toList().map{it.toModel()})
}

@Transactional(readOnly = true)
@GetMapping(RoutePaths.EXPORT_LIBRARY, produces = [MediaType.APPLICATION_JSON_VALUE])
@ResponseBody
fun exportLibrary(
@AuthenticationPrincipal user: Jwt?
): HttpEntity<TaskResult> {
if (!appConfig.allowPublicSearching && user === null) {
throw GeneralApiException("Unauthorized", HttpStatus.UNAUTHORIZED)
}
if (!oAuthHelper.hasRole(appConfig.roleAdmin)) {
throw GeneralApiException("OSMT user must have an Admin role.", HttpStatus.UNAUTHORIZED)
}

val task = CsvTask(collectionUuid = "FullLibrary")
taskMessageService.enqueueJob(TaskMessageService.skillsForFullLibraryCsv, task)

return Task.processingResponse(task)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,6 @@ class TaskMessageService {
const val publishSkills = "batch-publish-skills"
const val updateCollectionSkills = "update-collection-skills"
const val skillsForCollectionCsv = "collection-skills-csv-process"
const val skillsForFullLibraryCsv = "full-library-skills-csv-process"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,60 @@ package edu.wgu.osmt.richskill
import edu.wgu.osmt.BaseDockerizedTest
import edu.wgu.osmt.HasDatabaseReset
import edu.wgu.osmt.HasElasticsearchReset
import edu.wgu.osmt.RoutePaths.EXPORT_LIBRARY
import edu.wgu.osmt.SpringTest
import edu.wgu.osmt.api.model.ApiSearch
import edu.wgu.osmt.collection.CollectionEsRepo
import edu.wgu.osmt.config.AppConfig
import edu.wgu.osmt.csv.BatchImportRichSkill
import edu.wgu.osmt.csv.RichSkillRow
import edu.wgu.osmt.jobcode.JobCodeEsRepo
import edu.wgu.osmt.keyword.KeywordEsRepo
import edu.wgu.osmt.mockdata.MockData
import edu.wgu.osmt.security.OAuthHelper
import edu.wgu.osmt.task.CsvTask
import edu.wgu.osmt.task.Task
import edu.wgu.osmt.task.TaskMessageService
import edu.wgu.osmt.task.TaskResult
import edu.wgu.osmt.task.TaskStatus
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeAll
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.mockito.Mockito
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.security.core.Authentication
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority
import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.test.util.ReflectionTestUtils
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.util.UriComponentsBuilder
import java.time.Instant
import java.util.*


@Transactional
internal class RichSkillControllerTest @Autowired constructor(
override val richSkillEsRepo: RichSkillEsRepo,
val taskMessageService: TaskMessageService,
val oAuthHelper: OAuthHelper,
val appConfig: AppConfig,
override val collectionEsRepo: CollectionEsRepo,
override val keywordEsRepo: KeywordEsRepo,
override val jobCodeEsRepo: JobCodeEsRepo
): SpringTest(), BaseDockerizedTest, HasDatabaseReset, HasElasticsearchReset {

var authentication: Authentication = Mockito.mock(Authentication::class.java)

@Autowired
lateinit var richSkillController: RichSkillController

Expand All @@ -36,9 +66,11 @@ internal class RichSkillControllerTest @Autowired constructor(
private lateinit var mockData : MockData
val nullJwt : Jwt? = null


@BeforeAll
fun setup() {
mockData = MockData()
ReflectionTestUtils.setField(appConfig, "roleAdmin", "ROLE_Osmt_Admin");
}

@Test
Expand Down Expand Up @@ -149,4 +181,43 @@ internal class RichSkillControllerTest @Autowired constructor(
assertThat(result.body?.get(0)?.operationType).isEqualTo("Insert")
assertThat(result.body?.get(0)?.user).isEqualTo("Batch Import")
}


@Disabled
@Test
fun testExportLibrary() {

val securityContext: SecurityContext = Mockito.mock(SecurityContext::class.java)
SecurityContextHolder.setContext(securityContext)

val attributes: MutableMap<String, Any> = HashMap()
attributes["email"] = "j.chavez@wgu.edu"

val authority: GrantedAuthority = OAuth2UserAuthority("ROLE_Osmt_Admin", attributes)
val authorities: MutableSet<GrantedAuthority> = HashSet()
authorities.add(authority)
Mockito.`when`(securityContext.authentication).thenReturn(authentication)
Mockito.`when`(SecurityContextHolder.getContext().authentication.authorities).thenReturn(authorities)


val responseHeaders = HttpHeaders()
responseHeaders.add("Content-Type", MediaType.APPLICATION_JSON_VALUE)
val headers : MutableMap<String, Any> = HashMap()
headers["key"] = "value"
val notNullJwt : Jwt? = Jwt("tokenValue", Instant.MIN, Instant.MAX,headers,headers)
val csvTaskResult = TaskResult(UUID.randomUUID().toString(),MediaType.APPLICATION_JSON_VALUE,TaskStatus.Processing, EXPORT_LIBRARY)


val service = mockk<TaskMessageService>()
every { service.enqueueJob(any(), any()) } returns Unit
mockkStatic(CsvTask::class)
mockkStatic(TaskResult::class)
every { Task.processingResponse(any()) } returns HttpEntity(csvTaskResult)

val result = richSkillController.exportLibrary(user = notNullJwt)
assertThat(result.body?.uuid).isNotBlank()
}



}