From eee1f7ca73355791f8920dfae53757a5622c0efe Mon Sep 17 00:00:00 2001 From: Moritz Horn Date: Thu, 29 Jan 2026 18:35:27 +0100 Subject: [PATCH 1/3] fix bulk update, import endYear handling, roles update & list udpate tracking --- server/grails-app/conf/application.groovy | 3 ++ .../org/gokb/BulkPackageImportService.groovy | 2 +- .../org/gokb/ComponentUpdateService.groovy | 15 ++++-- .../org/gokb/EzbCollectionService.groovy | 1 + .../services/org/gokb/OrgRolesService.groovy | 47 +++++++++++++++++++ .../services/org/gokb/TippService.groovy | 12 +++-- .../groovy/org/gokb/BulkImportSpec.groovy | 1 + 7 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 server/grails-app/services/org/gokb/OrgRolesService.groovy diff --git a/server/grails-app/conf/application.groovy b/server/grails-app/conf/application.groovy index 4380d6d6d..d5ca4424d 100644 --- a/server/grails-app/conf/application.groovy +++ b/server/grails-app/conf/application.groovy @@ -57,6 +57,7 @@ grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/register/start', access: ['permitAll']], [pattern: '/register/forgotPassword', access: ['permitAll']], [pattern: '/register/forgotPasswordExt', access: ['permitAll']], + [pattern: '/register/resetPasswordExt', access: ['permitAll']], [pattern: '/public/**', access: ["hasAnyRole('ROLE_ADMIN', 'ROLE_POWERUSER') and isFullyAuthenticated()"]], [pattern: '/package/**', access: ['permitAll']], [pattern: '/packages/**', access: ['permitAll']], @@ -379,6 +380,8 @@ globalSearchTemplates = [ [heading:'Primary URL', property:'primaryUrl'], [heading:'Provider', property:'provider?.name', link:true], [heading:'Status', property:'status?.value',sort:'status'], + [heading:'Date Created', property:'dateCreated',sort:'dateCreated'], + [heading:'Last Updated', property:'lastUpdated',sort:'lastUpdated'], ] ] ], diff --git a/server/grails-app/services/org/gokb/BulkPackageImportService.groovy b/server/grails-app/services/org/gokb/BulkPackageImportService.groovy index 809981774..ec9fb6c86 100644 --- a/server/grails-app/services/org/gokb/BulkPackageImportService.groovy +++ b/server/grails-app/services/org/gokb/BulkPackageImportService.groovy @@ -323,7 +323,7 @@ class BulkPackageImportService { // No end year } else if (cobj.end_year instanceof Integer) { - if (cobj.end_year < 1700 || cobj.start_year > 9999) { + if (cobj.end_year < 1700 || cobj.end_year > 9999) { errors['end_year'] = [message: "Package years must be between 1700 and 9999!"] } else if (!cobj.start_year) { diff --git a/server/grails-app/services/org/gokb/ComponentUpdateService.groovy b/server/grails-app/services/org/gokb/ComponentUpdateService.groovy index 4be2e4ef6..0db6888e8 100644 --- a/server/grails-app/services/org/gokb/ComponentUpdateService.groovy +++ b/server/grails-app/services/org/gokb/ComponentUpdateService.groovy @@ -153,11 +153,11 @@ class ComponentUpdateService { def new_variant_name = component.ensureVariantName(variant.variantName, type, locale) } } - else if (variant instanceof String && variant.trim() && !variants.find { it.variantName == name }) { + else if (variant instanceof String && variant.trim() && !variants.find { it.variantName == variant }) { // Add the variant name. - log.debug("Adding variantName ${name} to ${component} ..") + log.debug("Adding variantName ${variant} to ${component} ..") - def new_variant_name = component.ensureVariantName(name) + def new_variant_name = component.ensureVariantName(variant) // Add to collection. if (new_variant_name) { @@ -333,6 +333,11 @@ class ComponentUpdateService { } } } + + if (hasChanged) { + component.lastSeen = new Date().getTime() + } + hasChanged } @@ -355,7 +360,7 @@ class ComponentUpdateService { def pkg = null if (params.pkg) { - pkg = Package.get(params.int('pkg')) + pkg = Package.findByUuid(params.pkg) ?: Package.get(params.int('pkg')) if (!pkg) { result.result = 'ERROR' @@ -374,7 +379,7 @@ class ComponentUpdateService { def items = componentLookupService.restLookup(user, cls, params, null, true).data - if (cls == TitleInstancePackagePlatform && tipps_pkg && field == 'status') { + if (cls == TitleInstancePackagePlatform && pkg && field == 'status') { def status_rdv = params.int('_value') ? RefdataValue.get(params.int('_value')) : RefdataCategory.lookup('KBComponent.Status', params['_value']) if (pkg && isUserCurator(pkg, user) && status_rdv?.owner?.label == 'KBComponent.Status') { diff --git a/server/grails-app/services/org/gokb/EzbCollectionService.groovy b/server/grails-app/services/org/gokb/EzbCollectionService.groovy index f1356657e..49eeccc35 100644 --- a/server/grails-app/services/org/gokb/EzbCollectionService.groovy +++ b/server/grails-app/services/org/gokb/EzbCollectionService.groovy @@ -213,6 +213,7 @@ class EzbCollectionService { def date_changed = item.ezb_collection_deactivated_date.substring(0, 10) + ' 00:00:00' obj.retireAt(dateFormatService.parseTimestamp(date_changed)) + obj.save(flush: true) result.report[ARCHIVED_TYPE].retired++ } diff --git a/server/grails-app/services/org/gokb/OrgRolesService.groovy b/server/grails-app/services/org/gokb/OrgRolesService.groovy new file mode 100644 index 000000000..566606c44 --- /dev/null +++ b/server/grails-app/services/org/gokb/OrgRolesService.groovy @@ -0,0 +1,47 @@ +package org.gokb + +import org.gokb.cred.* + +class OrgRolesService { + + public Map addMissingRoles() { + Map result = [new_providers: 0, new_publishers: 0] + RefdataValue status_current = RefdataCategory.lookup(KBComponent.RD_STATUS, KBComponent.STATUS_CURRENT) + RefdataValue rdv_publisher = RefdataCategory.lookup('Org.Role', 'Publisher') + RefdataValue rdv_platform_provider = RefdataCategory.lookup('Org.Role', 'Platform Provider') + RefdataValue combo_publisher = RefdataCategory.lookup('Combo.Type', 'TitleInstance.Publisher') + RefdataValue combo_plt_provider = RefdataCategory.lookup('Combo.Type', 'Platform.Provider') + + def qry_string = '''from Org as o + where status = :sc + and exists ( + select 1 from Combo + where ( + fromComponent = o + or toComponent = o + ) + and type = :ct + ) + and :rp not member of o.roles''' + + List missing_provider_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_plt_provider, rp: role_provider]) + + missing_provider_orgs.each { org -> + org.addToRoles(rdv_platform_provider) + org.save(flush: true) + } + + result.new_providers = missing_provider_orgs.size() + + List missing_publisher_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_publisher, rp: role_publisher]) + + missing_publisher_orgs.each { org -> + org.addToRoles(rdv_publisher) + org.save(flush: true) + } + + result.new_publishers = missing_publisher_orgs.size() + + return result + } +} \ No newline at end of file diff --git a/server/grails-app/services/org/gokb/TippService.groovy b/server/grails-app/services/org/gokb/TippService.groovy index c7d6cf067..38602186a 100644 --- a/server/grails-app/services/org/gokb/TippService.groovy +++ b/server/grails-app/services/org/gokb/TippService.groovy @@ -845,13 +845,15 @@ class TippService { } public Boolean hasOpenReviews(pid) { + int total = 0 + ReviewRequest.withNewSession { RefdataValue status_open = RefdataCategory.lookup("ReviewRequest.Status", "Open") RefdataValue combo_tipps = RefdataCategory.lookup("Combo.Type", "Package.Tipps") RefdataValue manual_review_type = RefdataCategory.lookup("ReviewRequest.StdDesc", 'Manual Request') def qry = '''select count(*) from ReviewRequest as rr - where ( + where (( rr.componentToReview.id = :pid and rr.stdDesc != :mr ) @@ -865,13 +867,13 @@ class TippService { and type = :ct ) ) - ) + )) and rr.status = :so''' - def total = ReviewRequest.executeQuery(qry, [pid: pid, mr: manual_review_type, ct: combo_tipps, so: status_open])[0] - - return total > 0 + total = ReviewRequest.executeQuery(qry, [pid: pid, mr: manual_review_type, ct: combo_tipps, so: status_open])[0] } + + return total > 0 } @Transactional diff --git a/server/src/integration-test/groovy/org/gokb/BulkImportSpec.groovy b/server/src/integration-test/groovy/org/gokb/BulkImportSpec.groovy index 5a8c3dac1..c23b3bc35 100644 --- a/server/src/integration-test/groovy/org/gokb/BulkImportSpec.groovy +++ b/server/src/integration-test/groovy/org/gokb/BulkImportSpec.groovy @@ -174,6 +174,7 @@ class BulkImportSpec extends Specification { package_created_date: null, package_changed_date: null, start_year: 2025, + end_year: 2025, other_package_identifiers: [ [ namespace: 'isil', From b265f0548cfb418c0afaa6cc0140727ff21d7716 Mon Sep 17 00:00:00 2001 From: Moritz Horn Date: Fri, 30 Jan 2026 18:05:14 +0100 Subject: [PATCH 2/3] org roles sync --- .../org/gokb/AdminController.groovy | 9 +++++++++ .../org/gokb/IntegrationController.groovy | 19 ++++++++++++++++--- .../groovy/org/gokb/IngestKbartRun.groovy | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/server/grails-app/controllers/org/gokb/AdminController.groovy b/server/grails-app/controllers/org/gokb/AdminController.groovy index 8567cc147..78acdb55f 100644 --- a/server/grails-app/controllers/org/gokb/AdminController.groovy +++ b/server/grails-app/controllers/org/gokb/AdminController.groovy @@ -31,6 +31,7 @@ class AdminController { def uploadAnalysisService def jobManagerService def curatoryGroupAlertingService + def orgRolesService CleanupService cleanupService ConcurrencyManagerService concurrencyManagerService TippService tippService @@ -571,6 +572,14 @@ class AdminController { render(view: "logViewer", model: logViewer()) } + def addMissingOrgRoles() { + log.debug("Adding missing Org roles based on existing component links") + + def result = orgRolesService.addMissingRoles() + + render result as JSON + } + def setupAcl() { diff --git a/server/grails-app/controllers/org/gokb/IntegrationController.groovy b/server/grails-app/controllers/org/gokb/IntegrationController.groovy index a08d07b06..426f282b5 100644 --- a/server/grails-app/controllers/org/gokb/IntegrationController.groovy +++ b/server/grails-app/controllers/org/gokb/IntegrationController.groovy @@ -302,11 +302,14 @@ class IntegrationController { def user = springSecurityService.currentUser def assert_errors = false; def jsonOrg = request.JSON + boolean fullsync = false + + if (params.fullsync == "true" && user.adminStatus) { + fullsync = true + } try { Org.withTransaction { - - Org located_or_new_org if (jsonOrg.uuid) { @@ -436,6 +439,8 @@ class IntegrationController { // roles log.debug("Role Processing: ${jsonOrg.roles}"); + def existing_roles = located_or_new_org.roles + jsonOrg.roles.each { r -> log.debug("Adding role ${r}"); def role = RefdataCategory.lookup("Org.Role", r) @@ -445,8 +450,16 @@ class IntegrationController { } } + if (fullsync) { + existing_roles.each { r -> + if (!jsonOrg.roles.contains(r.value)) { + located_or_new_org.removeFromRoles(r) + } + } + } + // Core data... - componentUpdateService.ensureCoreData(located_or_new_org, jsonOrg, false, user) + componentUpdateService.ensureCoreData(located_or_new_org, jsonOrg, fullsync, user) log.debug("Attempt to save - validate: ${located_or_new_org}"); diff --git a/server/src/main/groovy/org/gokb/IngestKbartRun.groovy b/server/src/main/groovy/org/gokb/IngestKbartRun.groovy index 67cb0ba29..37c0322a9 100644 --- a/server/src/main/groovy/org/gokb/IngestKbartRun.groovy +++ b/server/src/main/groovy/org/gokb/IngestKbartRun.groovy @@ -943,7 +943,7 @@ class IngestKbartRun { log.debug("TIPP ${tipp.id} info check: ${tipp.name}, ${tipp.url}") if (tipp.validate()) { - if (ingest_systime) { + if (ingest_systime && ingest_systime > tipp.lastSeen) { log.debug("Update last seen on tipp ${tipp.id} - set to ${ingest_date} (${tipp.lastSeen} -> ${ingest_systime})") tippService.updateLastSeen(tipp, ingest_systime) } From 93e29b656a92fcb298c3d605590777a2a7c74492 Mon Sep 17 00:00:00 2001 From: Moritz Horn Date: Mon, 2 Feb 2026 17:51:31 +0100 Subject: [PATCH 3/3] fix role update --- server/grails-app/services/org/gokb/OrgRolesService.groovy | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/grails-app/services/org/gokb/OrgRolesService.groovy b/server/grails-app/services/org/gokb/OrgRolesService.groovy index 566606c44..d1ac84a70 100644 --- a/server/grails-app/services/org/gokb/OrgRolesService.groovy +++ b/server/grails-app/services/org/gokb/OrgRolesService.groovy @@ -24,19 +24,21 @@ class OrgRolesService { ) and :rp not member of o.roles''' - List missing_provider_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_plt_provider, rp: role_provider]) + List missing_provider_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_plt_provider, rp: rdv_platform_provider]) missing_provider_orgs.each { org -> org.addToRoles(rdv_platform_provider) + org.lastSeen = System.currentTimeMillis() org.save(flush: true) } result.new_providers = missing_provider_orgs.size() - List missing_publisher_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_publisher, rp: role_publisher]) + List missing_publisher_orgs = Org.executeQuery(qry_string, [sc: status_current, ct: combo_publisher, rp: rdv_publisher]) missing_publisher_orgs.each { org -> org.addToRoles(rdv_publisher) + org.lastSeen = System.currentTimeMillis() org.save(flush: true) }