import com.dvelop.d3.server.core.D3Interface import com.dvelop.d3.server.exceptions.D3Exception import com.google.gson.Gson import groovy.json.JsonSlurper import groovy.transform.Field import org.apache.http.HttpEntity import org.apache.http.client.methods.CloseableHttpResponse import org.apache.http.client.methods.HttpDelete import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpPost import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.HttpClientBuilder import org.apache.http.util.EntityUtils import java.nio.charset.StandardCharsets /* * Dieses Skript loescht alle Fristen und Aufgaben fuer einen bestimmten Vertrag aus dem DBS Case Manager Contract. * * Erstellung: 12.2024 d.velop/mtiel * Optimierung: 05.2025 */ // Start of script D3Interface d3 = getProperty("d3") as D3Interface def scriptName = getClass().getName() d3.log.info("groovyhook - START Script ${scriptName}") // Konfiguration def batchSize = 100 // Größe der Batches für SQL-Abfrage und Verarbeitung def ddfIntContractNo = 11 // DB-Position der Eigenschaft interne Vertragsnummer def onlyTerms = false // Wenn nur die Fristen geloescht werden sollen, dann true setzen def onlyTasks = false // Wenn nur die Aufgaben geloescht werden sollen, dann true setzen def logDirectory = new File("E:\\d3work\\LOGS\\LOG_$scriptName") // Bitte hier den Pfad zum Logverzeichnis eintragen @Field String baseUri = "https://d3dev.int.hlg.de" // Bitte hier die Basis URL eintragen @Field String apiKey = "OJRD7qrEhuoIzM5Pt6M59qApakhyNrA/8My81PPx0/ULs+IisvBdZC6GnhcGTzKRwf4ndOtcsQmNby8YPa+D+mfUFsJGjkEsqhLX3h0N8sg=&_z_A0V5ayCRMk4iQs2RWKEDd9HrFriKdSm-G67jqTxNwqW1jZf2OP2l5b7LkBOKnISHL4YtCPCOz81OVhQgE0TQsWylfWnv1" // Bitte in der oberen Zeile den API Key fuer den User (wie d3ddecsTaskAPIKey) zum Suchen und Loeschen von Aufgaben eintragen // Ende Konfiguration def today = new Date() def formattedDate = today.format("yyyyMMdd") if (!logDirectory.exists()) { logDirectory.mkdir() } @Field StringBuilder logBuilder = new StringBuilder() def logFile = new File(logDirectory.path + "\\${formattedDate}_${System.currentTimeMillis()}_${scriptName}.txt") logBuilder.append("Info:\t$scriptName - Logfile" + System.getProperty("line.separator")) def offset = 0 // Offset für die SQL-Abfrage (zur Batch-Verarbeitung) // Schleife zur Verarbeitung der SQL-Abfrage in Batches while (true) { def internalContractNumbers = d3.sql.executeAndGet(""" WITH Vertragsnummern AS ( SELECT DISTINCT t.object_id AS intContractNo FROM terms_term t WHERE NOT EXISTS ( SELECT 1 FROM firmen_spezifisch f WHERE f.dok_dat_feld_$ddfIntContractNo = t.object_id ) UNION ALL SELECT DISTINCT d.internal_contract_number AS intContractNo FROM dbsCase_activity d WHERE NOT EXISTS ( SELECT 1 FROM firmen_spezifisch f WHERE f.dok_dat_feld_$ddfIntContractNo = d.internal_contract_number ) ) SELECT DISTINCT intContractNo FROM Vertragsnummern ORDER BY intContractNo OFFSET ? ROWS FETCH NEXT ? ROWS ONLY """, [offset, batchSize]) if (internalContractNumbers?.isEmpty()) { break // Keine weiteren Daten vorhanden, Schleife beenden } internalContractNumbers?.each { def internalContractNo = it.intContractNo //Loeschen der Fristen fuer die Vertragsnummer if (!onlyTasks) { d3.log.info("groovyhook - Es sollen die Fristen fuer den Vertrag ${internalContractNo} geloescht werden!") logBuilder.append("Info:\tEs sollen die Fristen fuer den Vertrag ${internalContractNo} geloescht werden!" + System.getProperty("line.separator")) def termIds = d3.sql.executeAndGet("SELECT DISTINCT id FROM terms_term WHERE object_id = ?", [internalContractNo]) if (!termIds || termIds.isEmpty()) { d3.log.info("groovyhook - Keine Fristen fuer den Vertrag ${internalContractNo} gefunden.") logBuilder.append("Info:\t\tKeine Fristen fuer den Vertrag ${internalContractNo} gefunden." + System.getProperty("line.separator")) } else { // Tabellen und Abhaengigkeiten def termTables = ["terms_idp_ids" : "Term_id", "terms_term_metadata": "Term_id", "terms_term_rem_esc" : "term_id", "terms_term_callback": "term_id", "terms_term_links" : "Term_id", "terms_term" : "id", "terms_interval" : "id"] termIds."id"?.each { id -> termTables.each { table, column -> try { def deleteQuery = "DELETE FROM ${table} WHERE ${column} = ?" if (d3.sql.execute(deleteQuery, [id]) == 1) { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht." + System.getProperty("line.separator")) } else { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} nicht gefunden.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} nicht gefunden." + System.getProperty("line.separator")) } } catch (D3Exception e) { error = true d3.log.error("groovyhook - Fehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}") logBuilder.append("Error:\t\tFehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}" + System.getProperty("line.separator")) } } } } logBuilder.append("\t\t--------------------------------------------------------------------------------" + System.getProperty("line.separator")) } // Loeschen von Aufgaben fuer die Dokumenten ID if (!onlyTerms) { logBuilder.append("Info\tEs sollen die Aktivitaeten fuer den Vertrag ${internalContractNo} geloescht werden!" + System.getProperty("line.separator")) def activityIds = d3.sql.executeAndGet("SELECT DISTINCT id FROM terms_activity WHERE context_id = ?", [internalContractNo]) if (!activityIds || activityIds.isEmpty()) { d3.log.info("groovyhook - Keine Aktivitaeten fuer den Vertrag ${internalContractNo} gefunden.") logBuilder.append("Info:\t\tKeine Aktivitaeten fuer den Vertrag ${internalContractNo} gefunden." + System.getProperty("line.separator")) } def activityTables = ["terms_activity_detail": "activity_id", "terms_activity_data" : "id", "terms_activity" : "id"] activityIds."id"?.each { id -> activityTables.each { table, column -> try { def deleteQuery = "DELETE FROM ${table} WHERE ${column} = ?" if (d3.sql.execute(deleteQuery, [id]) == 1) { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht." + System.getProperty("line.separator")) } else { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} nicht gefunden.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} nicht gefunden." + System.getProperty("line.separator")) } } catch (D3Exception e) { error = true d3.log.error("groovyhook - Fehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}") logBuilder.append("Error:\t\tFehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}" + System.getProperty("line.separator")) } } } logBuilder.append("\t\t--------------------------------------------------------------------------------" + System.getProperty("line.separator")) logBuilder.append("Info:\tEs sollen die Aufgaben fuer den Vertrag ${internalContractNo} geloescht werden!" + System.getProperty("line.separator")) def caseActivityIds = d3.sql.executeAndGet("SELECT DISTINCT act_id FROM dbsCase_activity WHERE internal_contract_number = ?", [internalContractNo]) def caseActivityTables = ["dbsCase_activity_recip": "activity_id", "dbsCase_activity_cond" : "act_id", "dbsCase_activity" : "act_id"] caseActivityIds."act_id"?.each { id -> caseActivityTables.each { table, column -> try { def deleteQuery = "DELETE FROM ${table} WHERE ${column} = ?" if (d3.sql.execute(deleteQuery, [id]) == 1) { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} erfolgreich geloescht." + System.getProperty("line.separator")) } else { if (table == "dbsCase_activity_cond") { d3.log.debug("groovyhook - Es gibt keine Bedingungen für die CMC Aufgabe ${id}.") logBuilder.append("Info:\t\tEs gibt keine Bedingungen für die CMC Aufgabe ${id}." + System.getProperty("line.separator")) } else { d3.log.debug("groovyhook - Eintrag aus Tabelle ${table} mit ID ${id} nicht gefunden.") logBuilder.append("Info:\t\tEintrag aus Tabelle ${table} mit ID ${id} nicht gefunden." + System.getProperty("line.separator")) } } } catch (D3Exception e) { error = true d3.log.error("groovyhook - Fehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}") logBuilder.append("Error:\t\tFehler beim Loeschen der Eintraege aus Tabelle ${table} mit ID ${id}: ${e}" + System.getProperty("line.separator")) } } } def sessionApiKey = getAuthSession(d3) //Ermitteln der Task ID def uriTaskSearch = "${baseUri}/task/api/tasks/search" CloseableHttpClient client = HttpClientBuilder.create().build() try { HttpPost post = new HttpPost(uriTaskSearch) // JSON Inhalt def body = """{ "orderBy": "received", "orderDir": "ASC", "filter": { "metadata": { "key": [ "internalCaseNumber" ], "values": [ "$internalContractNo" ] } } }""" StringEntity params = new StringEntity(body, "UTF-8") post.addHeader("authorization", "Bearer " + sessionApiKey) post.addHeader("content-type", "application/json") post.setEntity(params) CloseableHttpResponse response = client.execute(post) try { if (response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201) { def js = new JsonSlurper() def parsedJson = js.parseText(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8)) def taskIds = parsedJson.tasks?.id?.collect { it.toString() } def taskSubjects = parsedJson.tasks?.subject?.collect { it.toString() } if (!taskIds || taskIds.isEmpty()) { d3.log.info("groovyhook - Es gibt keine Aufgaben zum Vertrag ${internalContractNo}") logBuilder.append("Info:\t\tEs gibt keine Aufgaben zum Vertrag ${internalContractNo}" + System.getProperty("line.separator")) } else { for (def taskId : taskIds) { for (def taskSubject : taskSubjects) { d3.log.info("groovyhook - Task ID zum Vertrag ${internalContractNo}: ${taskId}") logBuilder.append("Info:\t\tTask ID zum Vertrag ${internalContractNo}: ${taskId}" + System.getProperty("line.separator")) //Loeschen der Aufgabe def uriTaskDelete = "${baseUri}/task/tasks/${taskId}" def delete = new HttpDelete(uriTaskDelete) delete.addHeader("authorization", "Bearer " + sessionApiKey) response = client.execute(delete) try { if (response.getStatusLine().getStatusCode() == 200 || response.getStatusLine().getStatusCode() == 201) { d3.log.info("groovyhook - Task $taskSubject zum Vertrag ${internalContractNo} wurde erfoglreich geloescht") logBuilder.append("Info:\t\tTask $taskSubject zum Vertrag ${internalContractNo} wurde erfoglreich geloescht" + System.getProperty("line.separator")) } else if (!(response.getStatusLine().getStatusCode() == 404)) { d3.log.error("groovyhook - Task $taskId zum Vertrag ${internalContractNo} mit Betreff $taskSubject konnte nicht geloescht werden: HTTP ${response.getStatusLine().getStatusCode()}") logBuilder.append("Error:\t\tTask $taskId zum Vertrag ${internalContractNo} mit Betreff $taskSubject konnte nicht geloescht werden: HTTP ${response.getStatusLine().getStatusCode()}" + System.getProperty("line.separator")) } } catch (D3Exception e) { d3.log.error("groovyhook - Fehler beim Ausführen von TaskDelete: ${e}") logBuilder.append("Error:\t\tFehler beim Ausführen von TaskDelete: ${e}" + System.getProperty("line.separator")) } finally { response.close() } } } } } else { d3.log.error("groovyhook - Task ID zum Vertrag ${internalContractNo} konnte nicht ermittelt werden: HTTP ${response.getStatusLine().getStatusCode()}") logBuilder.append("Error:\t\tTask ID zum Vertrag ${internalContractNo} konnte nicht ermittelt werden: HTTP ${response.getStatusLine().getStatusCode()}" + System.getProperty("line.separator")) } } finally { response.close() } } catch (D3Exception e) { d3.log.error("groovyhook - Fehler beim Ausführen von TaskSearch: ${e}") logBuilder.append("Error:\t\tFehler beim Ausführen von TaskSearch: ${e}" + System.getProperty("line.separator")) } logBuilder.append("\t\t--------------------------------------------------------------------------------" + System.getProperty("line.separator")) } } offset += batchSize // Offset für den nächsten Batch erhöhen } d3.log.info("groovyhook - END Script ${scriptName}") logBuilder.append("Info:\tEND Script ${scriptName}" + System.getProperty("line.separator")) logFile.write(logBuilder.toString()) def getAuthSession(D3Interface d3) { def lAuthSession = null def lSessionExpire = null HashMap returnMap = doLogin(d3) if (returnMap != null) { lAuthSession = returnMap.get("AuthSessionId") lSessionExpire = returnMap.get("Expire") } if (lAuthSession == null || lAuthSession == "") { d3.log.error("groovyhook - Keine AuthSession erhalten!") logBuilder.append("Error:\t\tKeine AuthSession erhalten!" + System.getProperty("line.separator")) } return lAuthSession } def doLogin(D3Interface d3) { HashMap returnMap = null def loginStatusCode = 0 CloseableHttpClient client = HttpClientBuilder.create().build() try { HttpGet loginCall = new HttpGet(baseUri + "/identityprovider/login") loginCall.addHeader("authorization", "Bearer " + apiKey) loginCall.addHeader("origin", baseUri) loginCall.addHeader("accept", "application/json") loginCall.addHeader("charset", "utf-8") CloseableHttpResponse loginResponse = client.execute(loginCall) try { loginStatusCode = loginResponse.getStatusLine().getStatusCode() if (loginStatusCode == 200 || loginStatusCode == 201) { HttpEntity entity = loginResponse.getEntity() String json = EntityUtils.toString(entity, StandardCharsets.UTF_8) Gson gson = new Gson() returnMap = gson.fromJson(json, HashMap.class) } else { d3.log.error("Error ${loginStatusCode} waehrend des Logins!") logBuilder.append("Error:\t\tError ${loginStatusCode} waehrend des Logins!" + System.getProperty("line.separator")) } } finally { loginResponse.close() } } catch (Exception e) { d3.log.error("groovyhook - Fehler waehrend des Logins: ${e}") logBuilder.append("Error:\t\tFehler waehrend des Logins: ${e}" + System.getProperty("line.separator")) } finally { client.close() } return returnMap }