erste version der DB dateien erstellt
This commit is contained in:
628
database/packages/pck_net_storage.pkb
Normal file
628
database/packages/pck_net_storage.pkb
Normal file
@@ -0,0 +1,628 @@
|
||||
create or replace package body pck_net_storage as
|
||||
|
||||
-- ==================== Private Helpers ====================
|
||||
|
||||
function f_build_url (
|
||||
i_object_key in varchar2 default null
|
||||
,i_action in varchar2 default null
|
||||
) return varchar2
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Baut die vollständige OCI Object Storage URL aus den Konfigurationsparametern.
|
||||
-- Entweder für eine Bucket-Action, ein einzelnes Objekt oder den Bucket-Root.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Objektschlüssel (Pfad im Bucket); null für Bucket-Root oder Action-URL
|
||||
-- i_action OCI Bucket-Action (z.B. renameObject); null für Objekt-URL
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: Vollständige URL als VARCHAR2
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_base varchar2(1024);
|
||||
begin
|
||||
l_base := 'https://objectstorage.'
|
||||
|| pck_system.f_get_par_wert_by_programmid('NET_STORAGE_REGION')
|
||||
|| '.oraclecloud.com/n/'
|
||||
|| pck_system.f_get_par_wert_by_programmid('NET_STORAGE_NAMESPACE')
|
||||
|| '/b/'
|
||||
|| pck_system.f_get_par_wert_by_programmid('NET_STORAGE_BUCKET');
|
||||
|
||||
if i_action is not null
|
||||
then
|
||||
return l_base || '/actions/' || i_action;
|
||||
elsif i_object_key is not null
|
||||
then
|
||||
-- Sonderzeichen kodieren, Schrägstriche im Key unverändert lassen
|
||||
return l_base || '/o/' || utl_url.escape(i_object_key, false);
|
||||
else
|
||||
return l_base || '/o';
|
||||
end if;
|
||||
end f_build_url;
|
||||
|
||||
procedure p_assert_allowed (i_object_key in varchar2)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Prüft den Objektschlüssel auf Path-Traversal-Angriffe und Tenant-Scope.
|
||||
-- Wirft Application Error -20004 bei Path Traversal, -20005 bei Scope-Verletzung.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Zu prüfender Objektschlüssel
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_tenant_prefix varchar2(256);
|
||||
begin
|
||||
if instr(i_object_key, '..') > 0
|
||||
then
|
||||
raise_application_error(-20004, 'Path traversal attempt detected');
|
||||
end if;
|
||||
|
||||
l_tenant_prefix := pck_system.f_get_par_wert_by_programmid('NET_STORAGE_TENANT_ID');
|
||||
|
||||
if l_tenant_prefix is not null and length(l_tenant_prefix) > 0
|
||||
then
|
||||
if substr(i_object_key, 1, length(l_tenant_prefix)) != l_tenant_prefix
|
||||
then
|
||||
raise_application_error(-20005, 'Access denied: outside tenant scope');
|
||||
end if;
|
||||
end if;
|
||||
end p_assert_allowed;
|
||||
|
||||
function f_make_request (
|
||||
i_method in varchar2
|
||||
,i_url in varchar2
|
||||
,i_body_clob in clob default null
|
||||
,i_body_blob in blob default null
|
||||
,i_content_type in varchar2 default null
|
||||
) return clob
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Führt einen HTTP-Request gegen die OCI Object Storage API aus.
|
||||
-- Wertet den HTTP-Statuscode aus und löst bei Fehler einen Application Error aus.
|
||||
-- Authentifizierung erfolgt über APEX Web Credential (NET_STORAGE_APEX_CREDENTIAL_ID).
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_method HTTP-Methode (GET, PUT, DELETE, POST, HEAD)
|
||||
-- i_url Vollständige Ziel-URL
|
||||
-- i_body_clob Optionaler Request-Body als CLOB (z.B. JSON)
|
||||
-- i_body_blob Optionaler Request-Body als BLOB (Binärinhalt)
|
||||
-- i_content_type Optionaler Content-Type Header
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: Response-Body als CLOB (bei HEAD-Requests leer)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_headers apex_web_service.vc_arr2;
|
||||
l_values apex_web_service.vc_arr2;
|
||||
l_response clob;
|
||||
l_status number;
|
||||
begin
|
||||
if i_content_type is not null
|
||||
then
|
||||
l_headers(1) := 'Content-Type';
|
||||
l_values(1) := i_content_type;
|
||||
end if;
|
||||
|
||||
l_response := apex_web_service.make_rest_request(
|
||||
p_url => i_url
|
||||
,p_http_method => i_method
|
||||
,p_body => coalesce(i_body_clob, empty_clob())
|
||||
,p_body_blob => coalesce(i_body_blob, empty_blob())
|
||||
,p_http_headers => l_headers
|
||||
,p_http_values => l_values
|
||||
,p_credential_static_id => pck_system.f_get_par_wert_by_programmid('NET_STORAGE_APEX_CREDENTIAL_ID')
|
||||
);
|
||||
|
||||
l_status := apex_web_service.g_status_code;
|
||||
|
||||
if l_status = 404
|
||||
then
|
||||
raise_application_error(-20001, 'Object not found');
|
||||
elsif l_status in (401, 403)
|
||||
then
|
||||
raise_application_error(-20002, 'OCI authentication failed');
|
||||
elsif l_status = 409
|
||||
then
|
||||
raise_application_error(-20007, 'Object already exists');
|
||||
elsif l_status >= 400
|
||||
then
|
||||
raise_application_error(-20006,
|
||||
'OCI API error ' || l_status || ': ' || dbms_lob.substr(l_response, 500, 1));
|
||||
end if;
|
||||
|
||||
return l_response;
|
||||
end f_make_request;
|
||||
|
||||
-- Interne Implementierung ohne Rechteprüfung — wird von f_list_objects und p_delete_folder genutzt
|
||||
function f_list_objects_internal (
|
||||
i_prefix in varchar2
|
||||
,i_delimiter in varchar2
|
||||
,i_start_with in varchar2
|
||||
,i_limit in number
|
||||
) return sys_refcursor
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Listet Objekte und Unterordner im Bucket ohne Rechte- oder Scope-Prüfung.
|
||||
-- Paginiert automatisch über nextStartWith bis alle Ergebnisse geladen sind.
|
||||
-- Wird von f_list_objects (öffentlich) und p_delete_folder intern genutzt.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_prefix Präfix / Pfad im Bucket (z.B. eingang/)
|
||||
-- i_delimiter Trennzeichen für Hierarchie-Simulation (/ für direkte Kinder, leer = rekursiv)
|
||||
-- i_start_with Optionaler Startpunkt für Paginierung
|
||||
-- i_limit Maximale Anzahl Ergebnisse (0 = unbegrenzt)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: Ref Cursor mit Spalten (object_name, object_size, last_modified, is_folder, etag)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_url varchar2(4000);
|
||||
l_response clob;
|
||||
l_result t_net_storage_tab := t_net_storage_tab();
|
||||
l_next_start varchar2(1024);
|
||||
l_cursor sys_refcursor;
|
||||
l_count number := 0;
|
||||
l_done boolean := false;
|
||||
l_cur_start varchar2(1024) := i_start_with;
|
||||
c_page_size constant number := 1000;
|
||||
begin
|
||||
while not l_done
|
||||
loop
|
||||
l_url := f_build_url()
|
||||
|| '?prefix=' || utl_url.escape(i_prefix, false)
|
||||
|| '&delimiter=' || utl_url.escape(i_delimiter, false)
|
||||
|| '&limit=' || c_page_size;
|
||||
|
||||
if l_cur_start is not null
|
||||
then
|
||||
l_url := l_url || '&start=' || utl_url.escape(l_cur_start, false);
|
||||
end if;
|
||||
|
||||
l_response := f_make_request('GET', l_url);
|
||||
|
||||
-- Dateien aus objects-Array einlesen
|
||||
for rec in (
|
||||
select jt.object_name
|
||||
,jt.object_size
|
||||
,jt.last_modified
|
||||
,jt.etag
|
||||
from json_table(l_response, '$.objects[*]'
|
||||
columns (
|
||||
object_name varchar2(1024) path '$.name'
|
||||
,object_size number path '$.size'
|
||||
,last_modified varchar2(50) path '$.timeModified'
|
||||
,etag varchar2(256) path '$.etag'
|
||||
)) jt
|
||||
)
|
||||
loop
|
||||
l_result.extend;
|
||||
l_result(l_result.last) := t_net_storage_row(
|
||||
rec.object_name
|
||||
,rec.object_size
|
||||
,to_date(substr(rec.last_modified, 1, 19), 'YYYY-MM-DD"T"HH24:MI:SS')
|
||||
,'N'
|
||||
,rec.etag
|
||||
);
|
||||
l_count := l_count + 1;
|
||||
|
||||
if i_limit > 0 and l_count >= i_limit
|
||||
then
|
||||
l_done := true;
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
-- Unterordner aus prefixes-Array einlesen
|
||||
if not l_done
|
||||
then
|
||||
for rec in (
|
||||
select jt.prefix_name
|
||||
from json_table(l_response, '$.prefixes[*]'
|
||||
columns (
|
||||
prefix_name varchar2(1024) path '$'
|
||||
)) jt
|
||||
)
|
||||
loop
|
||||
l_result.extend;
|
||||
l_result(l_result.last) := t_net_storage_row(
|
||||
rec.prefix_name
|
||||
,0
|
||||
,null
|
||||
,'Y'
|
||||
,null
|
||||
);
|
||||
l_count := l_count + 1;
|
||||
|
||||
if i_limit > 0 and l_count >= i_limit
|
||||
then
|
||||
l_done := true;
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
|
||||
-- Nächste Seite prüfen
|
||||
if not l_done
|
||||
then
|
||||
l_next_start := json_value(l_response, '$.nextStartWith');
|
||||
|
||||
if l_next_start is null
|
||||
then
|
||||
l_done := true;
|
||||
else
|
||||
l_cur_start := l_next_start;
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
open l_cursor for
|
||||
select t.object_name
|
||||
,t.object_size
|
||||
,t.last_modified
|
||||
,t.is_folder
|
||||
,t.etag
|
||||
from table(l_result) t;
|
||||
|
||||
return l_cursor;
|
||||
end f_list_objects_internal;
|
||||
|
||||
-- ==================== Öffentliche Funktionen ====================
|
||||
|
||||
function f_list_objects (
|
||||
i_prefix in varchar2
|
||||
,i_delimiter in varchar2 default '/'
|
||||
,i_start_with in varchar2 default null
|
||||
,i_limit in number default 0
|
||||
) return sys_refcursor
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Listet Objekte und Unterordner im Bucket mit Rechteprüfung und Scope-Validierung.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_prefix Präfix / Pfad im Bucket (z.B. eingang/)
|
||||
-- i_delimiter Trennzeichen für Hierarchie-Simulation (Standard: /)
|
||||
-- i_start_with Optionaler Startpunkt für Paginierung
|
||||
-- i_limit Maximale Anzahl Ergebnisse (0 = unbegrenzt)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: Ref Cursor mit Spalten (object_name, object_size, last_modified, is_folder, etag)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('LESEN_ALLES');
|
||||
p_assert_allowed(i_prefix);
|
||||
return f_list_objects_internal(i_prefix, i_delimiter, i_start_with, i_limit);
|
||||
end f_list_objects;
|
||||
|
||||
function f_download_object (i_object_key in varchar2) return blob
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Lädt ein einzelnes Objekt aus dem OCI Bucket als BLOB herunter.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Vollständiger Objektschlüssel im Bucket
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: Dateiinhalt als BLOB
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_response blob;
|
||||
l_status number;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('LESEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
l_response := apex_web_service.make_rest_request_b(
|
||||
p_url => f_build_url(i_object_key)
|
||||
,p_http_method => 'GET'
|
||||
,p_credential_static_id => pck_system.f_get_par_wert_by_programmid('NET_STORAGE_APEX_CREDENTIAL_ID')
|
||||
);
|
||||
|
||||
l_status := apex_web_service.g_status_code;
|
||||
|
||||
if l_status = 404
|
||||
then
|
||||
raise_application_error(-20001, 'Object not found: ' || i_object_key);
|
||||
elsif l_status in (401, 403)
|
||||
then
|
||||
raise_application_error(-20002, 'OCI authentication failed');
|
||||
elsif l_status >= 400
|
||||
then
|
||||
raise_application_error(-20006, 'OCI API error ' || l_status);
|
||||
end if;
|
||||
|
||||
return l_response;
|
||||
end f_download_object;
|
||||
|
||||
procedure p_upload_object (
|
||||
i_object_key in varchar2
|
||||
,i_content in blob
|
||||
,i_content_type in varchar2
|
||||
)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Lädt ein Objekt in den OCI Bucket hoch (PUT). Überschreibt vorhandene Objekte.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Zielpfad im Bucket
|
||||
-- i_content Dateiinhalt als BLOB
|
||||
-- i_content_type MIME-Type des Inhalts (z.B. application/octet-stream)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
l_response := f_make_request(
|
||||
i_method => 'PUT'
|
||||
,i_url => f_build_url(i_object_key)
|
||||
,i_body_blob => i_content
|
||||
,i_content_type => i_content_type
|
||||
);
|
||||
end p_upload_object;
|
||||
|
||||
procedure p_delete_object (i_object_key in varchar2)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Löscht ein einzelnes Objekt aus dem OCI Bucket (DELETE).
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Vollständiger Objektschlüssel im Bucket
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('ADMIN');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
l_response := f_make_request(
|
||||
i_method => 'DELETE'
|
||||
,i_url => f_build_url(i_object_key)
|
||||
);
|
||||
end p_delete_object;
|
||||
|
||||
procedure p_delete_folder (i_prefix in varchar2)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Löscht rekursiv alle Objekte unterhalb eines Präfixes im OCI Bucket.
|
||||
-- Pseudo-Ordner (is_folder = Y) werden übersprungen.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_prefix Ordnerpräfix (z.B. eingang/batch-001/)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_cursor sys_refcursor;
|
||||
l_object_name varchar2(1024);
|
||||
l_object_size number;
|
||||
l_last_modified date;
|
||||
l_is_folder varchar2(1);
|
||||
l_etag varchar2(256);
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('ADMIN');
|
||||
p_assert_allowed(i_prefix);
|
||||
|
||||
-- Alle Objekte im Prefix auflisten (kein Delimiter = rekursiv, alle Tiefen)
|
||||
l_cursor := f_list_objects_internal(
|
||||
i_prefix => i_prefix
|
||||
,i_delimiter => ''
|
||||
,i_start_with => null
|
||||
,i_limit => 0
|
||||
);
|
||||
|
||||
loop
|
||||
fetch l_cursor into l_object_name, l_object_size, l_last_modified, l_is_folder, l_etag;
|
||||
exit when l_cursor%notfound;
|
||||
|
||||
-- Nur echte Objekte löschen, keine Pseudo-Ordner
|
||||
if l_is_folder = 'N'
|
||||
then
|
||||
l_response := f_make_request(
|
||||
i_method => 'DELETE'
|
||||
,i_url => f_build_url(l_object_name)
|
||||
);
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
close l_cursor;
|
||||
exception
|
||||
when others
|
||||
then
|
||||
if l_cursor%isopen
|
||||
then
|
||||
close l_cursor;
|
||||
end if;
|
||||
raise;
|
||||
end p_delete_folder;
|
||||
|
||||
procedure p_rename_object (
|
||||
i_object_key in varchar2
|
||||
,i_new_name in varchar2
|
||||
)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Benennt ein Objekt innerhalb desselben Verzeichnisses um.
|
||||
-- Verwendet die OCI renameObject-Action (kein physisches Kopieren).
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Vollständiger Objektschlüssel des Quelldatei
|
||||
-- i_new_name Neuer Dateiname (ohne Pfad)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_prefix varchar2(1024);
|
||||
l_new_key varchar2(1024);
|
||||
l_body clob;
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
-- Verzeichnispfad aus dem aktuellen Key extrahieren
|
||||
if instr(i_object_key, '/') > 0
|
||||
then
|
||||
l_prefix := substr(i_object_key, 1, instr(i_object_key, '/', -1));
|
||||
else
|
||||
l_prefix := null;
|
||||
end if;
|
||||
|
||||
l_new_key := l_prefix || i_new_name;
|
||||
p_assert_allowed(l_new_key);
|
||||
|
||||
l_body := '{"sourceName":"' || replace(replace(i_object_key, '\', '\\'), '"', '\"')
|
||||
|| '","newName":"' || replace(replace(l_new_key, '\', '\\'), '"', '\"')
|
||||
|| '"}';
|
||||
|
||||
l_response := f_make_request(
|
||||
i_method => 'POST'
|
||||
,i_url => f_build_url(i_action => 'renameObject')
|
||||
,i_body_clob => l_body
|
||||
,i_content_type => 'application/json'
|
||||
);
|
||||
end p_rename_object;
|
||||
|
||||
procedure p_move_object (
|
||||
i_object_key in varchar2
|
||||
,i_target_prefix in varchar2
|
||||
)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Verschiebt ein Objekt in einen anderen Ordner im selben Bucket.
|
||||
-- Verwendet die OCI renameObject-Action (kein physisches Kopieren).
|
||||
-- Der Dateiname bleibt erhalten; nur der Pfad ändert sich.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Vollständiger Objektschlüssel der Quelldatei
|
||||
-- i_target_prefix Zielpräfix inkl. trailing Slash (z.B. verarbeitet/batch-001/)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_filename varchar2(1024);
|
||||
l_new_key varchar2(1024);
|
||||
l_body clob;
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
-- Dateinamen aus dem aktuellen Key extrahieren
|
||||
if instr(i_object_key, '/') > 0
|
||||
then
|
||||
l_filename := substr(i_object_key, instr(i_object_key, '/', -1) + 1);
|
||||
else
|
||||
l_filename := i_object_key;
|
||||
end if;
|
||||
|
||||
l_new_key := i_target_prefix || l_filename;
|
||||
p_assert_allowed(l_new_key);
|
||||
|
||||
l_body := '{"sourceName":"' || replace(replace(i_object_key, '\', '\\'), '"', '\"')
|
||||
|| '","newName":"' || replace(replace(l_new_key, '\', '\\'), '"', '\"')
|
||||
|| '"}';
|
||||
|
||||
l_response := f_make_request(
|
||||
i_method => 'POST'
|
||||
,i_url => f_build_url(i_action => 'renameObject')
|
||||
,i_body_clob => l_body
|
||||
,i_content_type => 'application/json'
|
||||
);
|
||||
end p_move_object;
|
||||
|
||||
procedure p_create_folder (
|
||||
i_prefix in varchar2
|
||||
,i_folder_name in varchar2
|
||||
)
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Legt einen neuen Ordner im OCI Bucket an.
|
||||
-- Ordner werden als leeres Objekt mit trailing Slash simuliert.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_prefix Übergeordneter Pfad inkl. trailing Slash (z.B. eingang/)
|
||||
-- i_folder_name Name des neuen Ordners (ohne Slash)
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Prozedur erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_folder_key varchar2(1024);
|
||||
l_response clob;
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('SCHREIBEN_ALLES');
|
||||
p_assert_allowed(i_prefix);
|
||||
|
||||
-- Ordner als leeres Objekt mit trailing Slash anlegen
|
||||
l_folder_key := i_prefix || i_folder_name || '/';
|
||||
p_assert_allowed(l_folder_key);
|
||||
|
||||
l_response := f_make_request(
|
||||
i_method => 'PUT'
|
||||
,i_url => f_build_url(l_folder_key)
|
||||
,i_body_blob => empty_blob()
|
||||
,i_content_type => 'application/octet-stream'
|
||||
);
|
||||
end p_create_folder;
|
||||
|
||||
function f_get_object_metadata (i_object_key in varchar2) return t_object_meta
|
||||
/*Kopf------------------------------------------------------------------------------------------------
|
||||
-- Beschreibung: Ruft die Metadaten eines Objekts per HEAD-Request ab (kein Download des Inhalts).
|
||||
-- Liest Größe, Content-Type, Last-Modified und ETag aus den Response-Headern.
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Parameter: i_object_key Vollständiger Objektschlüssel im Bucket
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- Rückgabe: t_object_meta Record mit object_name, object_size, last_modified, content_type, etag
|
||||
------------------------------------------------------------------------------------------------------
|
||||
-- MA Datum Änderung
|
||||
-- SCK 2026-04-08 Funktion erstellt
|
||||
------------------------------------------------------------------------------------------------Kopf*/
|
||||
is
|
||||
l_response clob;
|
||||
l_result t_object_meta;
|
||||
l_hdr_name varchar2(256);
|
||||
begin
|
||||
pck_mitarbeiterrecht.p_hat_recht('LESEN_ALLES');
|
||||
p_assert_allowed(i_object_key);
|
||||
|
||||
-- HEAD-Anfrage: leerer Response-Body, Metadaten in Response-Headern
|
||||
l_response := f_make_request(
|
||||
i_method => 'HEAD'
|
||||
,i_url => f_build_url(i_object_key)
|
||||
);
|
||||
|
||||
l_result.object_name := i_object_key;
|
||||
|
||||
for i in 1..apex_web_service.g_headers.count
|
||||
loop
|
||||
l_hdr_name := lower(apex_web_service.g_headers(i).name);
|
||||
|
||||
case l_hdr_name
|
||||
when 'content-length'
|
||||
then
|
||||
l_result.object_size := to_number(apex_web_service.g_headers(i).value);
|
||||
when 'content-type'
|
||||
then
|
||||
l_result.content_type := apex_web_service.g_headers(i).value;
|
||||
when 'last-modified'
|
||||
then
|
||||
-- HTTP RFC 7231 Format: "Thu, 01 Jan 2026 00:00:00 GMT"
|
||||
l_result.last_modified := to_date(
|
||||
apex_web_service.g_headers(i).value
|
||||
,'DY, DD MON YYYY HH24:MI:SS "GMT"'
|
||||
,'NLS_DATE_LANGUAGE=AMERICAN'
|
||||
);
|
||||
when 'etag'
|
||||
then
|
||||
l_result.etag := apex_web_service.g_headers(i).value;
|
||||
else
|
||||
null;
|
||||
end case;
|
||||
end loop;
|
||||
|
||||
return l_result;
|
||||
end f_get_object_metadata;
|
||||
|
||||
end pck_net_storage;
|
||||
/
|
||||
Reference in New Issue
Block a user