Vorlagen ergänzt

This commit is contained in:
2025-04-04 11:35:25 +02:00
parent 1b227f5179
commit 993e4e0ec2
14 changed files with 1141 additions and 0 deletions

BIN
_Vorlagen/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,71 @@
Dokumentarten:
SELECT dokuart AS Dokumentart, kue_dokuart AS Kürzel FROM arten_dokumente WHERE dokument_typ = 'd' AND kue_dokuart NOT LIKE '$%' ORDER BY dokuart
Aktenarten:
SELECT dokuart AS Aktenart, kue_dokuart AS Kürzel FROM arten_dokumente WHERE doku-ment_typ = 'a' AND kue_dokuart NOT LIKE '$%' ORDER BY dokuart
Wertemengen:
SELECT predef_val_text from doc_field_val_names ORDER BY predef_val_text
Werte in den Wertemengen:
SELECT dfvn.predef_val_text AS Wertemenge, dfv.value_char_allowed AS ErlaubterWert
FROM doc_field_val_names dfvn
JOIN doc_field_values dfv ON dfvn.predef_val_id = dfv.predef_value_id ORDER BY dfvn.predef_val_text, dfv.value_char_allowed
Erweiterte Eigenschaften:
SELECT repository_text AS "Erweiterte Eigenschaft", doc_field_nr_pref AS "Dok_dat_feld", da-ta_type AS "Typ", data_length AS "Länge" FROM field_repository WHERE repository_text NOT LIKE '$%' AND repository_text <> 'Logging-Typ' AND repository_text <> 'Logging-Datum';
Gruppen:
SELECT benutzergruppe AS d3Gruppe FROM benutzergruppen ORDER BY benutzergruppe
Berechtigungen:
SELECT roll_text AS Berechtigungsprofile FROM doc_roll_header ORDER BY roll_text
Rendition Regeln:
SELECT
dch.class_text AS Dokumentklasse,
tr.doc_extension AS Dateierweiterung,
CASE WHEN tr.tiff_event = 'N' THEN 'Neuer Version'
WHEN tr.tiff_event = 'I' THEN 'Neuimport'
WHEN tr.tiff_event = 'F' THEN 'Transfer in Freigabe'
WHEN tr.tiff_event = 'P' THEN 'Transfer in Prüfung'
WHEN tr.tiff_event = 'A' THEN 'Transfer in Archiv'
END AS Ereignis,
CASE WHEN tr.tiff_option = '1' THEN 'TIF'
WHEN tr.tiff_option = '2' THEN 'PDF'
ELSE '-'
END AS Zielformat,
CASE WHEN tr.ocr_option = '1' THEN 'Ja' ELSE 'Nein' END AS Verschlagwortung
FROM tiff_rules tr
JOIN doc_classes_header dch ON dch.class_shortcut = tr.class_shortcut ORDER BY dch.class_text
Abfrage um Regeln abzufragen, die nicht einer Dokumentklasse angehören:
SELECT
tr.class_shortcut AS Dokumentklasse,
tr.doc_extension AS Dateierweiterung,
CASE WHEN tr.tiff_event = 'N' THEN 'Neuer Version'
WHEN tr.tiff_event = 'I' THEN 'Neuimport'
WHEN tr.tiff_event = 'F' THEN 'Transfer in Freigabe'
WHEN tr.tiff_event = 'P' THEN 'Transfer in Prüfung'
WHEN tr.tiff_event = 'A' THEN 'Transfer in Archiv'
END AS Ereignis,
CASE WHEN tr.tiff_option = '1' THEN 'TIF'
WHEN tr.tiff_option = '2' THEN 'PDF'
ELSE '-'
END AS Zielformat,
CASE WHEN tr.ocr_option = '1' THEN 'Ja' ELSE 'Nein' END AS Verschlagwortung
FROM tiff_rules tr
WHERE tr.class_shortcut IS NULL
ORDER BY tr.class_shortcut

View File

@@ -0,0 +1,102 @@
import com.dvelop.d3.server.core.D3Interface
import java.text.SimpleDateFormat
import java.util.Date;
D3Interface d3 = getProperty("d3");
d3.log.info("Start Skript: Automatische Freigabe");
/**
* ----------------------Start Initialisierung----------------------------------------------
*/
int returnCode;
String currentDB;
final String BEARBEITUNG = "DOC_STAT_PROCESSING";
final String FREIGABE = "DOC_STAT_RELEASE";
final String PRUEFUNG = "DOC_STAT_VERIFICATION";
def docuIdList = [];
def dtsList = [];
/**
* ----------------------Ende Initialisierung-----------------------------------------------
*/
/**
* ----------------------Konfigurationsbereich allgemein------------------------------------
*/
//Zeitintervall (Tage) für die automatische Freigabe
int daysOff = 14;
//Angabe der relevanten Dokumentart-Kürzel
dtsList = ["KRDOK"];
//Angabe des ausführenden Benutzers
def d3User = "dvelop";
/**
* ----------------------Ende Konfigurationsbereich allgemein-------------------------------
*/
/**
* ----------------------Konfigurationsbereich SQL-------------------------------------------
*/
def dtsString = String.join("','", dtsList);
d3.log.info("Dokumentart(en): ${dtsString}");
//Datumsgrente ermitteln
def date = new SimpleDateFormat("dd.MM.yyyy").format(new Date() - daysOff);
d3.log.info("Datumsgrenze: ${date}");
//Prüfung des Datenbank-Servers
String dbServer = d3.config.value("db_server");
d3.log.info("Datenbank: ${dbServer}");
if(dbServer == "ORAC" || dbServer == "DB2") {
currentDB = "to_date('${date}','DD.MM.YYYY')";
}
if(dbServer == "MSQL") {
currentDB = "CONVERT(DATETIME, '${date}', 104)";
}
String sqlStm = """select firmen_spezifisch.doku_id as dokId from phys_datei
inner join firmen_spezifisch on (firmen_spezifisch.doku_id = phys_datei.doku_id)
where dokuart in ( '${dtsString}' )
and logi_verzeichnis in ('Be', 'Pr')
and last_update_attr <= ${currentDB}""";
d3.log.info("SQL: ${sqlStm}");
def resultset = d3.sql.executeAndGet(sqlStm);
docuIdList = resultset.collect{ it.dokId };
/**
* ----------------------Ende Konfigurationsbereich SQL---------------------------------------
*/
for(String id : docuIdList)
{
// Hole aktuellen Status des Dokuments
def currentDoc = d3.archive.getDocument(id, d3User );
def docStatus = currentDoc.getStatus();
d3.log.info("Aktuelle ID: ${id}");
if(docStatus.toString() == BEARBEITUNG || docStatus.toString() == PRUEFUNG)
{
returnCode = currentDoc.transfer("Freigabe", "", "Automatischer Statustransfer", false, 0, "");
if(returnCode != 0)
{
d3.log.error("Statustransfer 'Freigabe' für DokID: ${id} ist fehlgeschlafen! Fehlercode: ${returnCode}");
} else {
d3.log.info("Statustransfer 'Freigabe' für DokID: ${id} war erfolgreich!");
}
}
}
d3.log.info("Ende Skript: Automatische Freigabe");

View File

@@ -0,0 +1,38 @@
import com.dvelop.d3.server.Condition
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.DocumentType
import com.dvelop.d3.server.Entrypoint
import com.dvelop.d3.server.User
import com.dvelop.d3.server.core.D3
public class D3FolderTest{
@Entrypoint( entrypoint = "hook_insert_exit_20" ) //------------------------
@Condition( doctype = "DMIG" )
public int testCreateFolder( D3 d3, Document doc, def fileDest, def importOK, User user, DocumentType docTypeShort ){
// Step 1: Create Document-Object ---------------------
// Für den Aufruf von "folder_create" wird ein Dokument-Objekt benötigt. Wenn keines als Parameter zur Verfügung steht,
// so kann über die "Archive" Schnittstelle ein Dokument-Objekt für ein existierendes Dokument erzeugt werden.
// Dieses wird als Vorlage benutzt und dessen Attribute werden wie gewünscht angepasst.
def newDocObj = d3.archive.getDocument( "P000000001", "dvelop" ); // Das hier definierte Basis-Dokument legt den Typ fest!
newDocObj.type = "APERS"; // Leider scheint die Änderung des Dokumenttyps nicht möglich, dieser Eintrag wird ignoriert.
newDocObj.status = Document.DocStatus.DOC_STAT_RELEASE;
newDocObj.editor = "dvelop";
newDocObj.setText(1, "Bemerkungstext Zeile 1");
newDocObj.field[1] = "7896645";
newDocObj.field[80] = 0;
//newDocObj.field[60][1] = "Akte per folder_create - Attrib 60-1";
// ...
def error = d3.call.folder_create( newDocObj );
if( error ){
println "Fehler $error bei der Aktenanlage"
}
else {
println "Aktenanlage erfolgreich"
}
return 0;
} // end of testCreateFolder
} // end of D3FolderTest

View File

@@ -0,0 +1,33 @@
import groovy.sql.*;
public class PersonnelHooks {
// definition of entrypoint
public String username = "sa";
public String password = "password"
def sql_global ;
//*************************************** intiale Anmeldung an die DB
public PersonnelHooks(){
sql_global = Sql.newInstance("jdbc:sqlserver://10.95.6.177:1433;databaseName=D3ER",username, password);
}
// hook_insert_entry_10 für Bewerbungsdokumente----------------------------------------------------
@Entrypoint(entrypoint = "hook_insert_entry_10")
@Condition(doctype = [PersonnelConstants.g_DA_BEWERBERDOKUMENTE])
public int DbsInsertEntry10_3(D3Interface d3, User d3User, DocumentType docTypeShort, Document docObj) {
d3.log.info("[D3ECMPF] groovy hook insert_entry_10_3 $docTypeShort.id");
sql_global.eachRow("Select zeich_nr from phys_datei ")
{
d3.log.info("$it.zeich_nr");
}
}
// Ende hook_insert_entry_10 für Bewerbungsdokumente----------------------------------------------------
} // end of class

View File

@@ -0,0 +1,38 @@
//Dieses Skript erzeugt gezielt für Dokumente eine Rendition
//Ausgeführt wird dieses Skript per d.3 server interface, zuvor muss das SQL-Statement angepasst werden. Das SQL-Statement muss die Dokumenten-IDs der Dokumente liefern, für die eine Rendition erzeugt werden soll.
//Es muss ein Benutzer "scriptUser" angegeben werden, der volle Rechte für die entsprechenden Dokumente hat.
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.core.D3Interface
import com.dvelop.d3.server.exceptions.SQLException
import com.dvelop.d3.server.exceptions.D3Exception
import javax.swing.*;
String scriptName = getClass().getName()
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog (null, "Dies ist ein nicht supportetes Tool und ist nur fuer den internen Einsatz durch die d.velop AG gedacht.\nEs koennen erhebliche Schaeden in Ihrer d.3 Umgebung entstehen.\n \nWollen Sie wirklich fortfahren?\n ---------------------------------------------------\nThis is an unsupported tool and is only intended for internal use by d.velop AG.\nConsiderable damage can occur in your d.3 environment.\n \nAre you sure you want to continue?","Warning",dialogButton);
if(dialogResult == JOptionPane.NO_OPTION){
d3.log.info(scriptName + " - cancel")
return 0;
}
final def maxRows = 3000
String scriptUser = "d3_groovy"
int render_option = 2 //0=Nur OCR, 1=TIFF, 2=PDF, 3=TIFF und PDF
boolean ocr = true
boolean replace_doc = false
boolean overwrite = true //false=Auftrag für Rendition wird nur erzeugt, wenn noch keine Rendition vorhanden ist, true=Auftrag für Rendition wird immer erzeugt
String prio = "normal" //mögl. Wertelow, normal, high
def resultSet = d3.sql.executeAndGet("select doku_id from firmen_spezifisch where doku_id = 'A000016491'", maxRows)
d3.log.info (scriptName + " - "+resultSet.size()+" Documents found for rendition creation")
for (row in resultSet)
{
try {
def retval = d3.call.document_render ("", "", render_option, ocr, true, replace_doc, overwrite, row["doku_id"], scriptUser, "", 0, prio);
d3.log.info (scriptName + " - create rendition for " + row["doku_id"] + "--> " + retval)
}
catch (D3Exception e) {
d3.log.error("Error creating rendition " + e.getMessage())
}
}

View File

@@ -0,0 +1,45 @@
//Dieses Skript erstellt eine XML-Datei mit Gruppen-IDs die gelöscht werden sollen. Die XML-Datei kann per d.3 administration importiert werden.
//Ausgeführt wird dieses Skript per d.3 server interface, zuvor muss das SQL-Statement angepasst werden. Das SQL-Statement muss die Gruppen-IDs der zu löschenden Gruppen liefern.
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.core.D3Interface
import com.dvelop.d3.server.exceptions.SQLException
import com.dvelop.d3.server.exceptions.D3Exception
import javax.swing.*;
String scriptName = getClass().getName()
int dialogButton = JOptionPane.YES_NO_OPTION;
int dialogResult = JOptionPane.showConfirmDialog (null, "Dies ist ein nicht supportetes Tool und ist nur fuer den internen Einsatz durch die d.velop AG gedacht.\nEs koennen erhebliche Schaeden in Ihrer d.velop documents Umgebung entstehen.\n \nWollen Sie wirklich fortfahren?\n ---------------------------------------------------\nThis is an unsupported tool and is only intended for internal use by d.velop AG.\nConsiderable damage can occur in your d.velop documents environment.\n \nAre you sure you want to continue?","Warning",dialogButton);
if(dialogResult == JOptionPane.NO_OPTION){
d3.log.info(scriptName + " - cancel")
return 0;
}
final def maxRows = 3000
def resultSet = d3.sql.executeAndGet("select gruppen_id from benutzergruppen where benutzergruppe like '%GroupsToBeDeleted%'", maxRows)
if(resultSet.size() == 0){
d3.log.info (scriptName + " - no result for groups to be deleted")
JOptionPane.showMessageDialog(null, "No result for groups to be deleted.");
return 0
}
def now = new Date()
File file = new File("ext_groovy/"+scriptName+"_"+now.format("yyyyMMddHHmmss", TimeZone.getTimeZone('UTC'))+".xml")
//Schreibe Kopf der XML-Datei
file.append('<?xml version="1.0" encoding="utf-8"?>\n')
file.append('<master_data>\n')
for (row in resultSet){
d3.log.info (scriptName + " - preparing group " + row["gruppen_id"] + " for deletion")
file.append(' <group id="' + row["gruppen_id"] + '" action="DELETE"/>\n')
}
//Schreibe Fuß der XML-Datei
file.append('</master_data>')
d3.log.info (scriptName + " - Creation of transportfile ("+file+") finished. Please consider that result for groups to be deleted is correct.")
d3.log.info (scriptName + " - If result is correct the transportfile can be imported via d.3 administration.")
JOptionPane.showMessageDialog(null, "Creation of transportfile ("+file+") finished. Please consider that result for groups to be deleted is correct.\n If result is correct the transportfile can be imported via d.3 administration.");

View File

@@ -0,0 +1,58 @@
import com.dvelop.d3.server.core.D3
import groovy.json.JsonSlurper
import javax.net.ssl.HttpsURLConnection
/**
* Beispiel um Dokumente anhand einer Kategorie und einer Eigenschaft zu suchen und mit dem JSON arbeiten zu können
*/
void searchDocuments(D3 d3, String sessionId, String searchCategory, String searchPropertyKey, String searchPropertyValue) {
String searchFor = "?sourceid=/dms/r/$REPO_ID/source&sourcecategories=[\"$searchCategory\"]&sourceproperties={\"$searchPropertyKey\":[\"$searchPropertyValue\"]}"
String baseRequest = "$BASE_URI/dms/r/$REPO_ID/srm$searchFor"
HttpsURLConnection request = new URL(baseRequest).openConnection() as HttpsURLConnection
request.requestMethod = "GET"
request.setRequestProperty("Origin", BASE_URI)
request.setRequestProperty("Accept", "application/json")
request.setRequestProperty("Authorization", "Bearer $sessionId")
if (request.responseCode == 200) {
def json = request.inputStream.withCloseable { stream ->
new JsonSlurper().parse(stream as InputStream)
}
//Alle gefundenen Dokumente durchgehen
json.items?.each {
//Dateinamen mit Endung jedes Dokuments holen
String fileName = it.sourceProperties.find { property -> property.key == "property_filename" }.value
File file = new File(exportDirectory, fileName)
//Download starten
downloadDocument(d3, sessionId, it._links.mainblobcontent.href, file.getPath())
}
} else {
d3.log.error("Fehler bei der Suche nach Dokumenten $request.responseCode: $request.responseMessage")
}
}
/**
* Beispiel um ein Dokument herunter zu laden
*/
void downloadDocument(D3 d3, String sessionId, String downloadUrl, String filePath) {
String baseRequest = BASE_URI + downloadUrl
HttpsURLConnection request = new URL(baseRequest).openConnection() as HttpsURLConnection
request.requestMethod = "GET"
request.setRequestProperty("Origin", BASE_URI)
request.setRequestProperty("Accept", "application/json")
request.setRequestProperty("Authorization", "Bearer $sessionId")
if (request.responseCode == 200) {
d3.log.info("Starte Download von: " + downloadUrl)
request.inputStream.withCloseable { stream ->
new File(filePath) << stream.getBytes()
}
} else {
d3.log.error("Fehler beim Herunterladen von $baseRequest")
}
}

View File

@@ -0,0 +1,46 @@
import com.dvelop.d3.server.core.D3Interface;
import groovy.json.JsonSlurper;
String delReason = "Aufbewahrungsfrist abgelaufen";
String sqlGetDocIDs = """SELECT doc_id, delete_date, db_tables_data FROM doc_recycler WHERE delete_reason = '${delReason}'
AND delete_date >= TO_DATE('2019-11-29', 'YYYY-MM-DD')
AND doc_id NOT IN (SELECT dokuid FROM bla_loeschprotokoll)""";
D3Interface d3 = getProperty("d3");
try {
def mappingDocsSet = d3.sql.executeAndGet(sqlGetDocIDs);
mappingDocsSet.each {
String docID = it.doc_id;
String docTyp = "";
String docBemerkung = "";
String docIdentifier = "";
String docErstelldatum = "";
String docDelDate = it.delete_date.toString();
docDelDate = docDelDate.substring(0,10);//YYYY-MM-DD
def slurper = new JsonSlurper();
def docAttributes = slurper.parseText(it.db_tables_data);
d3.log.info(docAttributes.get("com.dvelop.d3.DocumentData").get("firmen_spezifisch").get("dok_dat_feld_23"));
docTyp = docAttributes.get("com.dvelop.d3.DocumentData").get("firmen_spezifisch").get("dok_dat_feld_41");
docBemerkung = docAttributes.get("com.dvelop.d3.DocumentData").get("phys_datei").get("text");
docIdentifier = docAttributes.get("com.dvelop.d3.DocumentData").get("firmen_spezifisch").get("dok_dat_feld_23");
docErstelldatum = docAttributes.get("com.dvelop.d3.DocumentData").get("firmen_spezifisch").get("dok_dat_feld_59");
if (!docErstelldatum?.trim())
{
docErstelldatum = docAttributes.get("com.dvelop.d3.DocumentData").get("phys_datei").get("datum_einbring");
}
docErstelldatum = docErstelldatum.substring(0,10);//YYYY-MM-DD
String sqlInsertLoschprotokoll = """INSERT INTO bla_loeschprotokoll (dokuid, typ, bemerkung, identifier, erstelldatum, loeschdatum)
VALUES ('$docID', '$docTyp', '$docBemerkung', '$docIdentifier', TO_DATE('$docErstelldatum', 'YYYY-MM-DD'), TO_DATE('$docDelDate', 'YYYY-MM-DD'))""";
try {
d3.sql.execute(sqlInsertLoschprotokoll);
} catch (Exception e) {
d3.log.error("Fehler " + e.getMessage() + " beim Schreiben von bla_loeschprotokoll");
}
}
} catch (Exception e) {
d3.log.error("Fehler " + e.getMessage() + " beim Lesen von doc_recycler");
}

View File

@@ -0,0 +1,148 @@
// Das Skript prueft die Felder
// - Erinnerungsdatum
// - Erinnerung an
// - Erinnerung verschickt
// und sendet abhaengig hiervon Erinnerungen an die hinterlegten Benutzer
// Importe
import groovy.sql.GroovyRowResult
import groovy.json.JsonOutput;
import groovy.json.JsonSlurper;
import com.dvelop.d3.server.exceptions.SQLException
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.DocumentType
import com.dvelop.d3.server.core.D3Interface
import javax.net.ssl.HttpsURLConnection;
import java.text.SimpleDateFormat
// #################################################################################
// Konfigurationsbereich
// #################################################################################
String versandModus = "1" // 0 = Keine Erinnerungen verschicken, nur Logs ausgeben, 1 = Erinnerungen verschicken
int repoIdErinnerungVerschickt = 97
int repoIdErinnerungAn = 98
int repoIdErinnerungsdatum = 99
int dbPosErinnerungVerschickt = 33
int dbPosErinnerungAn = 34
int dbPosErinnerungsdatum = 58
String apiServiceUser = "D3APIServi"
String baseURi = "https://meinHost.meineDomain.de"
String repoId = "xxx"
String ServiceAPIKey = "xxx"
// #################################################################################
// Ende Konfigurationsbereich
// #################################################################################
try{
d3.log.info("Starte Skript TH_sendReminder");
d3.log.info("Ermittle Dokumente zur Erinnerung")
// Dokumente suchen, fuer die noch keine Erinnerung verschickt wurde
// Und dessen Erinnerungsdatum in der Vergangenheit liegt
def sqlQuery = """select doku_id, dok_dat_feld_$dbPosErinnerungAn as ErinnerungAn
from firmen_spezifisch
where dok_dat_feld_$dbPosErinnerungAn is not null and dok_dat_feld_$dbPosErinnerungsdatum is not null and dok_dat_feld_$dbPosErinnerungVerschickt is null
and kue_dokuart in (
select kue_dokuart from fispe_titel_dokuart
where repository_id = ${repoIdErinnerungVerschickt}
intersect
select kue_dokuart from fispe_titel_dokuart
where repository_id = ${repoIdErinnerungAn}
intersect
select kue_dokuart from fispe_titel_dokuart
where repository_id = ${repoIdErinnerungsdatum}
)
and dok_dat_feld_$dbPosErinnerungsdatum < getdate()"""
def resultSet = d3.sql.executeAndGet(sqlQuery)
d3.log.info (resultSet.size() + " Dokumente ermittelt.")
if (resultSet.size() > 0)
{
// Ergebnis durchlaufen und Erinnerungen verschicken
resultSet.each
{
lDokId = it.get("doku_id")
lEmpfaenger = it.get("ErinnerungAn")
if (versandModus == "0")
{
d3.log.info ("Nur Test: Erinnerung zu " + it.get("doku_id") + " wuerde an " + it.get("ErinnerungAn") + " verschickt werden.")
}
else if (versandModus == "1")
{
d3.log.info ("Erinnerung zu " + lDokId + " wird an " + lEmpfaenger + " verschickt.")
//Auslesen der IDP Gruppen IDs
HttpsURLConnection taskAppRequest = new URL(baseURi + "/task/tasks").openConnection();
taskAppRequest.setRequestMethod("POST");
taskAppRequest.setRequestProperty("Origin", baseURi);
taskAppRequest.setRequestProperty("content-type", "application/json");
taskAppRequest.setRequestProperty("Authorization", "Bearer " + ServiceAPIKey);
taskAppRequest.setDoOutput(true);
//correlationKey zusammensetzen
UUID uuid = UUID.randomUUID();
String randomUUIDString = uuid.toString();
String jsonInputString = """{
"subject" : "Erinnerung zum Dokument",
"description" : "Das Erinnerungsdatum für das anliegende Dokument wurde erreicht.",
"assignees" : [${lEmpfaenger}],
"correlationKey" : ${randomUUIDString},
"context" : {
"key" : "COMMON",
"type" : "task",
"name" : "Allgemeine Erinnerung"
},
"dmsReferences" : [
{
"repoId" : ${repoId},
"objectId" : ${lDokId}
}
],
"_links" : {
"attachment" : { "href": "/dms/r/${repoId}/o2/${lDokId}"}
}
}""";
def response = taskAppRequest.getOutputStream().write(jsonInputString.getBytes("UTF-8"));
response = taskAppRequest.getResponseCode()
if (response == 200 || response == 201)
{
// Wenn erfolgreich, Feld "Erinnerung verschickt" aktualisieren
d3.log.info("Aufgabe erfolgreich angelegt")
Document currentDoc = d3.archive.getDocument(lDokId, apiServiceUser)
def date = new Date()
def dateTime = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss")
currentDoc.field[dbPosErinnerungVerschickt] = "Verschickt am " + dateTime.format(date)
currentDoc.updateAttributes(apiServiceUser, true)
}
else
{
d3.log.error("Fehlercode " + response + " bei Anlage der Aufgabe")
}
}
}
}
d3.log.info("Skript TH_sendReminder erfolgreich beendet.");
}
catch (SQLException e)
{
d3.log.error ("Dokumente loeschen: Fehler in Script aufgetreten!");
}

View File

@@ -0,0 +1,31 @@
//Dieses Skript stellt Dokumente aus dem Papierkorb wieder her.
//Ausgeführt wird dieses Skript per d.3 server interface, zuvor muss das SQL-Statement angepasst werden. Das SQL-Statement muss die Dokumenten-IDs der wiederherzustellenden Dokumente liefern.
//Es muss ein Benutzer "scriptUser" angegeben werden, der volle Rechte für die entsprechenden Dokumente hat. (Um den Aktenplan anzutriggern)
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.core.D3Interface
import com.dvelop.d3.server.exceptions.SQLException
import com.dvelop.d3.server.exceptions.D3Exception
String scriptName = getClass().getName()
// d.3 User which executes the restore and check of the folder schemes
String scriptUser = "d3_groovy"
final def maxRows = 3000
//Einzelne Dokumente/Akten anhand der ID
//def resultSet = d3.sql.executeAndGet("select doc_id from doc_recycler where doc_id = 'DocumentsToBeRestored'", maxRows)
//oder anhand Metadaten (hier dok_dat_feld_3 = Aktenzeichen) aus dem Papierkorb
def resultSet = d3.sql.executeAndGet("select doc_id, delete_date, delete_user from doc_recycler where to_char(delete_date, 'MM-DD-YYYY') = to_char(sysdate, 'MM-DD-YYYY') and delete_user = 'd3_async' and db_tables_data like '%\"dok_dat_feld_3\": \"A-000004-2022\"%'")
resultSet.each{
try {
d3.log.info ("Restoring document with ID " + it.doc_id)
d3.call.restore_from_history (0, it.doc_id, '');
d3.log.info ("Checking folder scheme for document with ID " + it.doc_id)
Document myDoc = d3.archive.getDocument(it.doc_id, scriptUser)
myDoc.checkFolderScheme(scriptUser)
} catch (D3Exception e) {
d3.log.error("Error checking folder scheme " + e.getMessage())
}
}

View File

@@ -0,0 +1,157 @@
import com.dvelop.d3.server.core.D3Interface
import javax.net.ssl.HttpsURLConnection
D3Interface d3 = getProperty( 'd3' ) as D3Interface
def LOG_PREFIX = 'taskAppMigration: '
/**
* Angabe des Hostnamens ohne Slash am Ende.
*/
String hostname = ""
/**
* Der API_KEY muss vor der Ausführung gesetzt werden
**/
String API_KEY = ""
/**
* Dieser User wird anstelle der gesperrten / nicht vorhandenen d.3-User in die wieder_vorlage geschrieben.
* d.3 user-id:
*/
String d3ServiceUserSender = ""
String d3ServiceUserReceiver = ""
def query = """\
SELECT DISTINCT
wv.sender wv_user,
ben.idp_id,
CASE
WHEN sia.sid IS NOT NULL THEN 1
ELSE 0
END
ist_gesperrt
FROM
wieder_vorlage wv
JOIN benutzer ben ON ben.benutzername = wv.sender
LEFT OUTER JOIN sid_assign sia ON
sia.auth_id = ben.benutzername
AND
sia.delete_flag = 0
AND
sia.sid = (
SELECT
sil.sid
FROM
sid_list sil
WHERE
sil.caption = 'Konto ist deaktiviert'
)
WHERE
wv.wv_typ = 'W'
AND
wv.sender != 'd3_async'
UNION ALL
SELECT DISTINCT
wv.benutzername wv_user,
ben.idp_id,
CASE
WHEN sia.sid IS NOT NULL THEN 1
ELSE 0
END
ist_gesperrt
FROM
wieder_vorlage wv
JOIN benutzer ben ON ben.benutzername = wv.benutzername
LEFT OUTER JOIN sid_assign sia ON
sia.auth_id = ben.benutzername
AND
sia.delete_flag = 0
AND
sia.sid = (
SELECT
sil.sid
FROM
sid_list sil
WHERE
sil.caption = 'Konto ist deaktiviert'
)
WHERE
wv.wv_typ = 'W'
""".stripIndent()
Closure<HttpsURLConnection> connection = { String url ->
URL theUrl = new URL( url )
HttpsURLConnection con = ( HttpsURLConnection ) theUrl.openConnection()
con.addRequestProperty( 'Authorization', 'Bearer ' + API_KEY )
con.addRequestProperty( 'Accept', 'application/json' )
con.setDoInput( true )
con.setDoOutput( true )
return con
}
def rows = d3.sql.executeAndGet( query )
List<String> brokenUsers = [ ]
int gesperrt = 0
int nichtinIdp = 0
int aktiv = 0
rows.each{
d3.log.error( LOG_PREFIX + it.wv_user + ": " + it.idp_id )
d3.log.info( LOG_PREFIX + 'looking up ' + it.wv_user )
if( it.ist_gesperrt ){
gesperrt++
if( !brokenUsers.contains( it.wv_user)){
brokenUsers.add( it.wv_user )
}
d3.log.info( LOG_PREFIX + "Der user '$it.wv_user' ist gesperrt." )
return
}
HttpsURLConnection con = connection( hostname + '/identityprovider/scim/users/' + it.idp_id )
con.connect()
if( con.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND ){
d3.log.info( LOG_PREFIX + "Der User $it.wv_user existiert nicht als user im IDP." )
con.disconnect()
con = connection( hostname + '/identityprovider/scim/Groups/' + it.idp_id )
con.connect()
if( con.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND ){
nichtinIdp++
d3.log.info( LOG_PREFIX + "Der User $it.wv_user existiert nicht als Gruppe im idp." )
if( !brokenUsers.contains( it.wv_user)){
brokenUsers.add( it.wv_user )
}
con.disconnect()
} else{
aktiv++
d3.log.info( LOG_PREFIX + "Der User $it.wv_user ist eine Gruppe im idp." )
}
} else{
aktiv++
d3.log.info( LOG_PREFIX + "Der User $it.wv_user ist im idp." )
}
}
def updateUser = 'UPDATE wieder_vorlage SET benutzername = ? WHERE benutzername = ?'
def updateSender = 'UPDATE wieder_vorlage SET sender = ? WHERE sender = ?'
d3.log.info( LOG_PREFIX + "Aktualisiere Nicht-IDP-User in Tabelle wieder_vorlage...")
brokenUsers.each{
d3.log.info( LOG_PREFIX + "Ersetze user $it in 'benutzername' durch Service-User $d3ServiceUserReceiver")
def changed = d3.sql.execute(updateUser, [d3ServiceUserReceiver, it])
d3.log.info( LOG_PREFIX + "Zeilen geändert: $changed")
d3.log.info( LOG_PREFIX + "Ersetze user $it in 'sender' durch Service-User $d3ServiceUserSender")
changed = d3.sql.execute(updateSender, [d3ServiceUserSender, it])
d3.log.info( LOG_PREFIX + "Zeilen geändert: $changed")
}
//Zur Sicherheit noch ein Commit ausführen, wenn kein Autocommit aktiv:
d3.sql.execute( 'Commit' )
d3.log.info( LOG_PREFIX + 'Abgeschlossen.' )
d3.log.info( LOG_PREFIX + "Anzahl gesperrter User: $gesperrt" )
d3.log.info( LOG_PREFIX + "Anzahl nicht registrierter IDP-User: $nichtinIdp" )
d3.log.info( LOG_PREFIX + "Anzahl aktiver User: $aktiv" )
d3.log.info( LOG_PREFIX + "Betroffene User: $brokenUsers" )

View File

@@ -0,0 +1,95 @@
import com.dvelop.d3.server.Document
import com.dvelop.d3.server.DocumentType
import com.dvelop.d3.server.User
import com.dvelop.d3.server.ValueSet
import com.dvelop.d3.server.Validation
import com.dvelop.d3.server.core.D3
import com.dvelop.d3.server.core.D3Interface
import com.dvelop.d3.server.exceptions.SQLException
import com.dvelop.d3.server.exceptions.D3Exception
import java.lang.annotation.*
import java.sql.SQLWarning;
import java.sql.Timestamp
/*
Script for updating documents
*/
// #################################################################################
// Configuration
// #################################################################################
def documentTypes = "('DDRA2', 'XXXXX')" // Document types, syntax like sql "where in "
def oldValue = "AVEVA" // Existing value in the defined categories
def newValue = "AVEVA" // Value to update
int dbPos = 33 // DB Position, TODO: Extend for mutli value fields, currently only for DB-Position 1 - 49
def updateCount = "1000" // Limit the number of documents to be updated - for testing
def LogFilePath = "D:\\d3logs\\updateDocuments.log"
def ErrorLogFilePath = "D:\\d3logs\\updateDocumentsError.log"
def logOnly = "0" // 1 = Only write document ids to logfile
def apiUser = "d3_hook" // User for api calls
boolean noHooks = true // Enable / disable update hooks
// #################################################################################
// End Configuration
// #################################################################################
d3.log.info("Start to update documents " + documentTypes)
d3.log.info("Old Value: " + oldValue)
d3.log.info("New Value: " + newValue)
def LogFile = new File(LogFilePath)
def ErrorLogFile = new File(ErrorLogFilePath)
LogFile.append("\n\rStart Update documents.")
int countUpdated = 0
int countUpdateError = 0
// Define SQL Query
def sqlQuery = "select top ${updateCount} doku_id from firmen_spezifisch where kue_dokuart in" + documentTypes + " and dok_dat_feld_$dbPos = '${oldValue}'"
def resultset = d3.sql.executeAndGet(sqlQuery)
if (resultset.size() > 0)
{
d3.log.info (resultset.size() + " documents found to update.")
LogFile.append("\n\r" + resultset.size() + " documents found to update.")
// Iterate through results
resultset.each
{
if (logOnly == "1")
{
LogFile.append("\n" + it.get("doku_id"))
countUpdated++
}
else
{
try
{
Document currentDoc = d3.archive.getDocument(it.get("doku_id"), apiUser)
currentDoc.field[dbPos] = newValue
currentDoc.updateAttributes(apiUser, noHooks)
LogFile.append("\n" + it.get("doku_id"))
countUpdated++
}
catch (Exception e)
{
d3.log.error ("Update documents: Error " + e + " in script!")
ErrorLogFile.append("\n" + e)
countUpdateError++
}
}
if (countUpdated % 100 == 0)
{
d3.log.info(countUpdated + " documents updated")
}
}
d3.log.info(countUpdated + " documents updated")
LogFile.append("\n\r" + countUpdated + " documents updated")
d3.log.info(countUpdateError + " documents with error")
LogFile.append("\n\r" + countUpdateError + " documents with error")
}

View File

@@ -0,0 +1,279 @@
//Dieses Skriptist ein Beispiel um Dokumente per DMS-Api hochzuladen
//Eine Beispieldatei wird bei Ausführung des Skripts erstellt
//In den Konfigurationsparametern muss für die Verbindung die Base-Url, RepoId und ein Api-Key angeben werden. Der Benutzer hinter dem Api-Key braucht mindestens die Berechtigungen "Dokument importieren" und "Eigenschaften aktualisieren"
//Per docType kann eine Dokumentart angeben werden. Die Eigenschaften können weiter unten im Skript (suche nach {to be configured}) angegeben werden. Dazu wird in diesem Beispiel das DMS-Default Mapping verwendet -> https://BASE-URL/dms/r/REPO-ID/source Beispiel: https://dms-test.local/dms/r/074ef140-250d-5a76-9c0c-311835e900e2/source
import groovy.json.JsonBuilder
import groovyx.net.http.FromServer
import groovyx.net.http.HttpBuilder
import groovyx.net.http.ContentTypes
import java.text.SimpleDateFormat
import java.time.YearMonth
class Configuration
{
// login data, used to perform operations which need authentication
// public static String API_KEY = "{yourApiKey}"
public static String API_KEY = "DOz4JkcUEl2nu+NWmh9ylqFtIz2bDtcA+UpWikbwFpqzHGlnQuaAj5XzM+6XKTI/IPDRQomgoTN6h8y2MDkojGHUeWvqN6qJaMEZ/wNxvXMIQyiCRsDgx4yqSmKmlfEM&_z_A0V5ayCSpMjWpAFIyddgzAJPQsAloshCGVuKs-6Sxam3gyUxmKVy45yP5jqdXY0HQyCzH9im5FHDT4fboog8erv_t0Anu"
// Base Url of d.3 system, to target API endpoints
// public static String baseUrl = "https://{yourUrl}.de"
public static String baseUrl = "https://w2019-sql2019en.vcloud.d-velop.de/"
// repository of destination, is used to target right repository for searching documents
public static String repositoryId = "1ddde1e8-2431-56c0-8cd1-b05dc1ae7dc3"
//public static String repositoryId = "{yourRepostoryId}"
//d.3 destination data
public static String docType = "DTEST"
//Do not edit these variables
public static String dmsUrl = "/dms/r/" + repositoryId
public static HttpBuilder httpBuilder = null
public static String authSessionId = ""
public static String sessionExpire = ""
public static File csvLog = null
public static String logDirPath = "./log/"
public static File logFile = new File(logDirPath + System.currentTimeMillis() + "_log.csv")
}
// must be allowed to set origin header
System.setProperty( "sun.net.http.allowRestrictedHeaders", "true")
// create httpBuilde with baseUrl
log("Create httpBuilder")
Configuration.httpBuilder = HttpBuilder.configure {
request.uri = Configuration.baseUrl
request.headers['Accept'] = 'application/json'
request.headers['Origin'] = Configuration.baseUrl
}
log("httpBuilder created")
login()
uploadDocument()
/**
* Function to upload document / create placeholder
*/
void uploadDocument(){
// check if login is valid
if(isLoginExpired()) {
login()
}
String requestUUID = UUID.randomUUID().toString()
// create new file
// check if directory "Tmp" exists
File tmpDir = new File("./Tmp/")
if(!tmpDir.exists() || !tmpDir.isDirectory()) {
// create directory for tmp files
tmpDir.mkdirs()
}
File tmpFile = new File("./Tmp/mydoc.hc")
tmpFile.createNewFile()
tmpFile.text = "New mydoc: " + System.currentTimeMillis()
Configuration.httpBuilder.post {
request.uri.path = Configuration.dmsUrl + "/blob/chunk/"
request.headers['Authorization'] = 'Bearer ' + Configuration.authSessionId
request.headers['Accept'] = 'application/hal+json'
request.headers['x-dv-request-id'] = requestUUID
request.contentType = ContentTypes.BINARY[0]
request.body = tmpFile.bytes
response.exception { e ->
log("RequestUUID: ${requestUUID} - Upload exception: ${e.message}")
}
response.failure { f ->
log("RequestUUID: ${requestUUID} - Upload failed: ${f.message}")
// if request failed because of "Unathorized" ir "Forbidden" try new login and then send request again
if(f.message.toString().equals("Unauthorized") || f.message.toString().equals("Forbidden") ) {
login()
}
}
response.success { s, bytes ->
// get header for Location
String locationUrl = FromServer.Header.find(s.getHeaders(), "Location").parsed
if(locationUrl != null && !locationUrl.equals("")) {
log("RequestUUID: ${requestUUID} - Upload of binary successful -> locationUrl: ${locationUrl} ")
//Now assign metadata to uploaded document
saveNewUploadedDocument(locationUrl)
}
}
}
}
/**
* Function to assign metadata to uploaded document
*/
void saveNewUploadedDocument(String locationUrl){
// check if login is valid
if(isLoginExpired()) {
login()
}
String requestUUID = UUID.randomUUID().toString()
Map bodyMap = new HashMap<>()
//Your file
bodyMap.put("filename", "mydoc.hc")
bodyMap.put("sourceCategory", Configuration.docType)
bodyMap.put("sourceId", Configuration.dmsUrl + "/source")
bodyMap.put("contentLocationUri", locationUrl)
List propertiesList = new ArrayList()
Map propertiesMap = new HashMap()
Map propertyMap1 = new HashMap<>()
Map propertyMap2 = new HashMap<>()
//ToDo: Adjust Key and value. Have a look at this URL to find out the keys for your metadata: https://BASE-URL/dms/r/REPO-ID/source Example: https://dms-test.local/dms/r/074ef140-250d-5a76-9c0c-311835e900e2/source
//Your metadata (single value) {to be configured}
propertyMap1.put("key", "1")
propertyMap1.put("values", ["myValue"])
propertiesList.add(propertyMap1)
propertiesMap.put("properties", propertiesList)
bodyMap.put("sourceProperties", propertiesMap)
//Your metadata (multi value) {to be configured}
propertyMap2.put("key", "12")
propertyMap2.put("values", ["myDocMultiValue1", "myDocMultiValue2"])
propertiesList.add(propertyMap2)
propertiesMap.put("properties", propertiesList)
bodyMap.put("sourceProperties", propertiesMap)
JsonBuilder jsonBuilder = new JsonBuilder()
jsonBuilder.content = bodyMap
Configuration.httpBuilder.post {
request.uri.path = Configuration.dmsUrl + "/o2m"
request.headers['Authorization'] = 'Bearer ' + Configuration.authSessionId
request.headers['Accept'] = 'application/hal+json'
request.headers['x-dv-request-id'] = requestUUID
request.contentType = ContentTypes.JSON[0]//'application/hal+json'
request.body = jsonBuilder.toPrettyString()
response.parser(ContentTypes.JSON[0]) {config, resp ->
String responseText = resp.inputStream.getText()
log("RequestUUID: ${requestUUID} - ResponseText: ${responseText}")
}
response.exception { e ->
log("RequestUUID: ${requestUUID} - Save uploaded file exception: ${e.message}")
}
response.failure { f ->
log("RequestUUID: ${requestUUID} - Save uploaded file failed: ${f.message}")
// if request failed because of "Unathorized" ir "Forbidden" try new login and then send request again
if(f.message.toString().equals("Unauthorized") || f.message.toString().equals("Forbidden") ) {
login()
}
}
response.success { s ->
log("RequestUUID: ${requestUUID} - Save uploaded file successful")
// get docId from Location Header
String locationHeader = FromServer.Header.find(s.getHeaders(), "Location").parsed
if(locationHeader != null && !locationHeader.equals("")) {
String[] locationParts = locationHeader.split("/o2m/")
if(locationParts.size() == 2) {
String[] secondParts = locationParts[1].split("\\?")
String docId = secondParts[0]
log("RequestUUID: ${requestUUID} - Save uploaded file successful: DocId - " + docId)
}
}
}
}
}
/**
* Function to perform login request
*/
void login() {
String requestUUID = UUID.randomUUID().toString()
Configuration.httpBuilder.get {
request.uri.path = '/identityprovider/login'
request.headers['Authorization'] = 'Bearer ' + Configuration.API_KEY
request.headers['x-dv-request-id'] = requestUUID
request.contentType = ContentTypes.URLENC
response.exception { e ->
log("RequestUUID: ${requestUUID} - Login exception")
}
response.failure { f ->
log("RequestUUID: ${requestUUID} - Login failed: ${f.message}")
}
response.success { s, json ->
log("RequestUUID: ${requestUUID} - Login success")
Configuration.authSessionId = json.getAt("authSessionId")
Configuration.sessionExpire = json.getAt("expire")
if(Configuration.authSessionId == null || Configuration.authSessionId.equals("") || Configuration.authSessionId.equals("null")) {
log("AuthSessionId not given with first letter small, try upper case")
Configuration.authSessionId = json.getAt("AuthSessionId")
}
if(Configuration.sessionExpire == null || Configuration.sessionExpire.equals("") || Configuration.sessionExpire.equals("null")) {
log("Expire not given with first letter small, try upper case")
Configuration.sessionExpire = json.getAt("Expire")
}
}
}
}
/**
* Function to check if authSessionId is given and still not expired
*
* @return boolean true if login is not valid
*/
boolean isLoginExpired() {
boolean result = false
if(Configuration.authSessionId == null || Configuration.authSessionId.equals("")) {
result = true
}
if(Configuration.sessionExpire == null || Configuration.sessionExpire.equals("")) {
result = true
} else {
// check if sessionExpire is grater then current timestamp
long nowTimestamp = System.currentTimeMillis()
// convert sessionExpire to timestamp
SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd'T'H:m:s.S'Z'")
Date expireDate = inputFormat.parse(Configuration.sessionExpire)
long expireTimestamp = expireDate.time
if(nowTimestamp>=expireTimestamp) {
result = true
}
}
return result
}
/**
* Function to log given message to log file and to console
* @param message
*/
void log(String message) {
String messageWithTimestamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(System.currentTimeMillis())) + " : ${message}"
println(messageWithTimestamp)
if(!Configuration.logFile.exists()) {
// check if directory exists
// check if directory "Log" exists
File logDir = new File(Configuration.logDirPath)
if(!logDir.exists() || !logDir.isDirectory()) {
// create directory for log files
logDir.mkdirs()
}
Configuration.logFile.createNewFile()
}
Configuration.logFile.append(messageWithTimestamp + "\n")
}