Skip to content
Draft
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
44 changes: 39 additions & 5 deletions server/grails-app/controllers/org/gokb/AdminController.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import org.hibernate.criterion.CriteriaSpecification
import org.springframework.security.access.annotation.Secured
import org.springframework.security.acls.domain.BasePermission

import java.time.LocalDateTime
import java.time.*
import java.util.concurrent.CancellationException

import grails.gorm.transactions.*
Expand Down Expand Up @@ -477,9 +477,9 @@ class AdminController {

def cacheSinglePackage() {
log.debug("Manual package caching for ID ${params.id}")
def result = [params: params, result: null]
Map result = [params: params, result: null]

def pkg = Package.findByUuid(params.id)
Package pkg = Package.findByUuid(params.id)

if (!pkg && params.long('id')) {
pkg = Package.get(params.long('id'))
Expand All @@ -503,8 +503,8 @@ class AdminController {

def deduplicatePackageTipps() {
log.debug("Manual TIPP deduplication for ID ${params.id}")
def result = [params: params, result: null]
def pkgId = params.int('id') ?: null
Map result = [params: params, result: null]
Long pkgId = params.long('id') ?: null

if (pkgId) {
Job j = concurrencyManagerService.createJob { job ->
Expand All @@ -519,6 +519,40 @@ class AdminController {
render(view: "logViewer", model: logViewer())
}

def revertLinkedTiIds() {
log.debug("Manual TIPP deduplication for ID ${params.id}")
Map result = [params: params, result: 'OK']
Long pkgId = params.long('id') ?: null
LocalDate linkDate

try {
linkDate = LocalDate.from(params.date)
}
catch (Exception e) {
result.result = 'ERROR'
result.message = 'Unable to parse date parameter!'
}

if (pkgId && linkDate) {
Job j = concurrencyManagerService.createJob { job ->
packageCleanupService.revertTitleIds(pkgId, linkDate, job)
}.startOrQueue()

j.description = "Deduplicating package TIPPs for package ${pkgId}"
j.type = RefdataCategory.lookupOrCreate('Job.Type', 'Package TI Id Cleanup')
j.startTime = new Date()

render(view: "logViewer", model: logViewer())
}
else {
result.result = 'ERROR'
response.status = 400

render result as JSON
}
}


def fetchEzbCollections() {
log.debug("Triggering EZB open collections sync")

Expand Down
76 changes: 76 additions & 0 deletions server/grails-app/services/org/gokb/PackageCleanupService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ import grails.gorm.transactions.Transactional

import groovy.util.logging.Slf4j

import java.time.*

import org.gokb.cred.*
import org.hibernate.HibernateException

@Slf4j
class PackageCleanupService {

def tippService
def titleAugmentService
def sessionFactory

def reactivateReplacedTipps(pid, Job j = null) {
def result = [result: 'OK', cases: 0, additionalDeletes: 0, total: 0]
Expand Down Expand Up @@ -101,4 +106,75 @@ class PackageCleanupService {

result
}

public Map revertTitleIds(Long pid, LocalDate date, Job j = null) {
Map result = [:]

try {
def session = sessionFactory.currentSession
result = processTitleIdCleanup(session, pid, date, j)
}
catch (HibernateException e) {
log.debug("Failed session lookup..")

Package.withNewSession { session ->
log.debug("revertTitleIds :: creating new session ..")
result = processTitleIdCleanup(session, pid, date, j)
}
}

result
}

private Map processTitleIdCleanup(session, Long pid, LocalDate date, Job job = null) {
Map result = [result: 'OK', cleanups: 0]
RefdataValue type_ids = RefdataCategory.lookup('Combo.Type', 'KBComponent.Ids')
RefdataValue type_ti_tipps = RefdataCategory.lookup('Combo.Type', 'TitleInstance.Tipps')
RefdataValue type_pkg_tipps = RefdataCategory.lookup('Combo.Type', 'Package.Tipps')
log.debug("revertTitleIds :: Processing id links for Package ${pid} between ${java.sql.Date.valueOf(date)} and ${java.sql.Date.valueOf(date.plusDays(1))} ..")

def deletion_candidates_qry = '''select id, fromComponent.id from Combo as cid
where type = :cti
and dateCreated between :dateStart and :dateEnd
and exists (
select 1 from Combo as ct
where type = :ctt
and fromComponent = cid.fromComponent
and exists (
select 1 from Combo as cp
where type = :ctp
and toComponent = ct.toComponent
and fromComponent.id = :pid
)
)
order by fromComponent.id'''

Map pars = [
pid: pid,
cti: type_ids,
ctt: type_ti_tipps,
ctp: type_pkg_tipps,
dateStart: java.sql.Date.valueOf(date),
dateEnd: java.sql.Date.valueOf(date.plusDays(1))
]

List delete_candidates = Combo.executeQuery(deletion_candidates_qry, pars)

for (c in delete_candidates) {
Combo ctd = Combo.get(c[0]).delete(flush: true)
result.cleanups++
TitleInstance ti = TitleInstance.get(c[1])

titleAugmentService.touchTitleTipps(ti, false)

if (result.cleanups % 50 == 0) {
session.flush()
session.clear()
}
}

job?.endTime = new Date()

result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.gokb

import grails.testing.mixin.integration.Integration

import java.time.*

import org.gokb.PackageCleanupService
import org.gokb.cred.*
import org.hibernate.SessionFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.annotation.Rollback
import org.springframework.transaction.annotation.Transactional

import spock.lang.Specification

@Integration
@Transactional
@Rollback
class PackageCleanupServiceSpec extends Specification {

@Autowired
PackageCleanupService packageCleanupService

def autoTimestampEventListener
LocalDate old_id_ld

def setup() {
RefdataValue status_deleted = RefdataCategory.lookup('KBComponent.Status', 'Deleted')
RefdataValue combo_type_id = RefdataCategory.lookup('Combo.Type', 'KBComponent.Ids')
IdentifierNamespace ns_doi = IdentifierNamespace.findByValue('doi')
old_id_ld = LocalDate.now().minusMonths(1)
Date old_id_date = Date.from(LocalDateTime.now().minusMonths(1).atZone(ZoneId.systemDefault()).toInstant())

BookInstance test_ti = BookInstance.findByName('PackageCleanupTitle')
Identifier new_id = Identifier.findByValue('10.2333/663633444') ?: new Identifier(value: '10.2333/663633444', namespace: ns_doi).save(flush: true, failOnError: true)
Identifier old_id = Identifier.findByValue('10.2333/345435535') ?: new Identifier(value: '10.2333/345435535', namespace: ns_doi).save(flush: true, failOnError: true)

if (!test_ti) {
test_ti = new BookInstance(name: 'PackageCleanupTitle').save(flush: true, failOnError: true)
test_ti.ids << new_id
test_ti.save(flush: true)

autoTimestampEventListener.withoutTimestamps {
Combo nc = new Combo(fromComponent: test_ti, toComponent: old_id, type: combo_type_id).save(flush: true, failOnError: true)
nc.dateCreated = old_id_date
nc.save(flush: true)
}
}

Package package_cleanup_pkg = Package.findByName('PackageCleanupPackage')
Org package_cleanup_provider = Org.findByName('PackageCleanupProvider') ?: new Org(name: 'PackageCleanupProvider').save(flush: true)
Platform package_cleanup_platform = Platform.findByName('PackageCleanupPlatform') ?: new Platform(name: 'PackageCleanupProvider', provider: package_cleanup_provider).save(flush:true)

if (!package_cleanup_pkg) {
package_cleanup_pkg = new Package(name: 'PackageCleanupPackage', provider: package_cleanup_provider, nominalPlatform: package_cleanup_platform).save(flush: true)
}

TitleInstancePackagePlatform package_cleanup_tipp = TitleInstancePackagePlatform.findByName('PackageCleanupTipp')

if (!package_cleanup_tipp) {
package_cleanup_tipp = new TitleInstancePackagePlatform(name: 'PackageCleanupTipp', url: 'https://test.com/gokbcleanuptest', hostPlatform: package_cleanup_platform, pkg: package_cleanup_pkg, title: test_ti).save(flush: true, failOnError: true)
}
}

def cleanup() {
TitleInstancePackagePlatform.findByName('PackageCleanupTipp')?.expunge()
BookInstance.findByName('PackageCleanupTitle')?.expunge()
}

void "test selective ID removal by date"() {
given:
Package package_cleanup_pkg = Package.findByName('PackageCleanupPackage')
BookInstance test_ti = BookInstance.findByName('PackageCleanupTitle')

Map total_pars = [
pid: package_cleanup_pkg.id,
cti: RefdataCategory.lookup('Combo.Type', 'KBComponent.Ids'),
ctt: RefdataCategory.lookup('Combo.Type', 'TitleInstance.Tipps'),
ctp: RefdataCategory.lookup('Combo.Type', 'Package.Tipps')
]

when:
Map result = packageCleanupService.revertTitleIds(package_cleanup_pkg.id, old_id_ld)
then:
def combos = Combo.executeQuery('''from Combo as cid
where type = :cti
and exists (
select 1 from Combo as ct
where type = :ctt
and fromComponent = cid.fromComponent
and exists (
select 1 from Combo as cp
where type = :ctp
and toComponent = ct.toComponent
and fromComponent.id = :pid
)
)
order by fromComponent.id''', total_pars)
combos.size() == 1
result.cleanups == 1
}
}