Is there a way to get pathparam from url with get_cgi_env? Example: https://clientes/{codigo}. I would like to get the value from :codigo pathparam.
Into handler GET, POST, PUT, etc. on endpoint it is possible to get the pathparam value but it's not clear how can to be done into ORDS prehook.
I have this function to get the complete url - the "QUERY_STRING" portion should give you the parameters
FUNCTION request_url RETURN VARCHAR2
IS
l_url VARCHAR2(1024);
BEGIN
l_url := owa_util.get_cgi_env('SERVER_NAME') ||':' ||
owa_util.get_cgi_env('SERVER_PORT') ||
owa_util.get_cgi_env('SCRIPT_NAME') ||
owa_util.get_cgi_env('PATH_INFO') ||
owa_util.get_cgi_env('QUERY_STRING');
RETURN l_url;
EXCEPTION WHEN VALUE_ERROR THEN
RETURN 'unable to retrieve request_url';
END request_url;
You can access all the CGI variables available via owa.cgi_var_name and owa.cgi_var_val (owa.num_cgi_vars for the count).
I have this running in my preHook:
pragma autonomous_transaction;
l_obj json_object_t := json_object_t();
l_json blob;
begin
for i in 1 .. owa.num_cgi_vars loop
l_obj.put(owa.cgi_var_name(i), owa.cgi_var_val(i));
end loop;
l_json := l_obj.to_blob;
insert into rest_access
(id, created, cgi_variables, current_schema)
values
(s_rest_access.nextval, sysdate, l_json, sys_context('userenv', 'current_schema'));
commit;
Lots of values that you have access to, including parameters.
To see a list of parameters after running it and logging requests, simply run
select *
from json_table((select json_dataguide(cgi_variables, dbms_json.format_flat) from rest_access),
'$[*]' columns( --
opath varchar2(200) path '$."o:path"',
otype varchar2(40) path '$.type',
olength number path '$."o:length"')) j;
Related
I tried the following code in SQL workshop and it ran. I tried the same code in an application after removing DBMS_OUT_PUT using it in a set value action and I get the error message: Ajax call returned server error ORA-20987: APEX - JSON.WRITER.NOT_OPEN - Contact your application administrator.
Details about this incident are available via debug id "354017". for Set Value. However, the debug logs don't provide any additional details.
What am I missing? It worked in the application a few days ago.
declare
l_request_url varchar2(32767);
l_content_type varchar2(32767);
l_content_length varchar2(32767);
l_response varchar2(10000);
l_body_clob clob;
l_name varchar2(200);
download_failed_exception exception;
j apex_json.t_values;
n_customer_id number;
begin
l_request_url := 'https://mysterysite.com/api/v3/customer';
APEX_JSON.initialize_clob_output;
APEX_JSON.open_object;
APEX_JSON.write('company', :P5_COMPANY);
APEX_JSON.write('bill_addr1', :P5_BILL_ADDR1);
APEX_JSON.write('bill_addr2', :P5_BILL_ADDR2);
APEX_JSON.write('bill_city', :P5_BILL_CITY);
APEX_JSON.write('bill_postcode', :P5_BILL_POSTCODE);
APEX_JSON.write('superuser_email', :P5__YOUR_EMAIL);
APEX_JSON.close_object;
l_body_clob :=APEX_JSON.get_clob_output;
APEX_JSON.free_output;
apex_web_service.g_request_headers.delete();
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/json';
l_response := apex_web_service.make_rest_request(
p_url => l_request_url
, p_http_method => 'POST'
, p_username => 'junk username'
, p_password => 'junkpassword'
, p_body => l_body_clob
);
if apex_web_service.g_status_code != 201 then
DBMS_OUTPUT.PUT_LINE('ERROR');
else
apex_json.Parse (j, l_response);
n_customer_id := apex_json.get_varchar2 (p_values => j, p_path => 'response.id');
DBMS_OUTPUT.PUT_LINE(n_customer_id);
end if;
end;
Product Build 22.2.1
Schema Compatibility 2022.10.07
Patch Version 1
Last Patch Time 12/26/2022 05:32:28 PM
Last DDL Time 12/26/2022 04:37:11 PM
Host Schema ORDS_PLSQL_GATEWAY
Application Owner APEX_220200
Not a complete solution, just a work around.
Replace the set value action with execute server side code action. In the code replace RETURN with apex_util.set_session_state ('item_name', value);
Try to set the preserve parameter to true in the call to initialize_clob_output.
In what context are you running this code? Another process probably also uses apex_json in the same code.
I have a problem with manually uploading the file from the SQL query. The file is sent to the database, but after re-filling the form (for the first time it only sends the completed form data). The file remains visible in the session and is as if stored until the next form filling. I know I can do this as Automatic Query Submission (DML) but I need to do it manually (I have a query that imports data into several tables at once)
DECLARE
l_blob BLOB;
l_filename VARCHAR2 (200);
l_mime_type VARCHAR2 (200);
l_token VARCHAR2 (32000);
BEGIN
l_filename := :P8_ATTACH;
l_mime_type := 'application/pdf');
DBMS_LOB.createtemporary (l_blob, FALSE, DBMS_LOB.SESSION);
FOR i IN 1 .. apex_application.g_f01.COUNT
LOOP
l_token := wwv_flow.g_f01 (i);
IF LENGTH (l_token) > 0
THEN
DBMS_LOB.append
(dest_lob => l_blob,
src_lob => to_blob
(UTL_ENCODE.base64_decode
(UTL_RAW.cast_to_raw (l_token)
)
)
);
END IF;
END LOOP;
IF DBMS_LOB.getlength (l_blob) IS NOT NULL
THEN
UPDATE REZERV
SET ATTACH = l_blob,
MIMETYPE = l_mime_type,
FILENAME = l_filename
WHERE ID = :P8_ID;
END IF;
END;
Have you considered
'Purge file at' = 'End of request'
or
'Source -> Used' = 'Always replacing session state'
Requirement -
Below fields to be displayed on a APEX page for any Jira issue created.
Issue Number/Issue Id
Summary
Description
Status
Assignee
Example, user01 and user02 both having access to Oracle APEX and Jira. user01 created 3 issues and user02 created 5 issues in Jira. Now when user01 who logs into Oracle APEX, should see 3 issues and when user02 who logs into Oracle APEX, should see 5 issues on a APEX page.
https://jira.local.com/jira/rest/api2
I'm new to APEX Rest service call and request to all of you to provide some sample APEX code to call Jira REST API using username/password for the above requirement.
Thanks all.
I have done something similar before. In my case, the goal was to get all the issues of project PRJ001 (Jira Project Key) from Jira and store them in a local database table (J_ISSUES), periodically, so I've created a Job that executed the following procedure from time to time:
create or replace PROCEDURE "JIRA_SYNC_ISSUES" as
var_response CLOB;
var_counter number := 0;
var_total number := 1;
var_prj_key varchar2(10);
begin
var_prj_key := 'PRJ001';
var_total := 1;
var_counter := 0;
while var_total > var_counter
loop
apex_session.create_session (p_app_id => 107, p_page_id => 1, p_username => 'USERNAME01');
var_response:= apex_web_service.make_rest_request(
p_url => 'https://yourcompany.atlassian.net/rest/api/2/search?jql=project="'|| var_prj_key ||'"&maxResults=100&startAt=' || var_counter || '',
p_http_method => 'GET',
p_credential_static_id => 'oud_rest'
);
SELECT JSON_VALUE(var_response, '$.total' RETURNING NUMBER) into var_total
FROM DUAL;
for i in (SELECT *
FROM
JSON_TABLE(var_response, '$.issues[*]'
COLUMNS (
key VARCHAR2(100) PATH '$.key',
prj_key VARCHAR2(100) PATH '$.fields.project.key',
status VARCHAR2(100) PATH '$.fields.status.name',
updated VARCHAR2(100) PATH '$.fields.updated',
assignee VARCHAR2(100) PATH '$.fields.assignee.name',
time_spent NUMBER PATH '$.fields.timespent'
)))
loop
begin
insert into j_issues (jis_key, jis_jpr_key, jis_status, jis_updated, jis_assignee, jis_time_spent)
values (i.key,
i.prj_key,
i.status,
to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
i.assignee,
i.time_spent);
exception
when dup_val_on_index then
update j_issues
set jis_jpr_key = i.prj_key,
jis_status = i.status,
jis_updated = to_timestamp(substr(i.updated,1,10)||' '||substr(i.updated,12,8),'YYYY-MM-DD HH24:MI:SS'),
jis_assignee = i.assignee,
jis_time_spent = i.time_spent
where jis_key = i.key;
end;
var_counter := var_counter + 1;
end loop;
end loop;
end jira_sync_issues;
In the first part it is authenticating and making the call to the API. In the second, it takes the var_response and inserts it into the required table.
For the first part, I've read this: https://www.jmjcloud.com/blog/simplifying-apex_web_service-oauth2-client-credentials
For the second: https://docs.oracle.com/database/121/SQLRF/functions092.htm
Notice the var_counter and var_total variables. They are used to iterate through the Jira responses, because there is a limit of items being retrieved in each response. So, if you are expecting more than that limit, you should make more calls to retrieve them.
If the volume of issues is big, there are advantages in doing a scheduled sync like this instead of letting the user wait for the entire result. After the data is in your database, you can just query it as usual.
Let me know if it helps ;)
I have a dynamic action doing the below ,
Submit page ,
Successful Alert message,
Log out and redirect to another website (www.google.com),
And I have two required item in page.
When pressed the button and the item is null ,the successful Alert message appears and after that the system shows the error (the item is required). How can I show the successful alert message only when the process and validation are done without errors ,and when ok is pressed in the alert message redirect to website and log out from the sessions
There are different ways you could approach this. You're currently using a mix of Dynamic Actions and page-level validations and processes that aren't going to play well together. I suggest you move all the logic to Dynamic Actions. Here are step by step instructions to do what I think you're trying to do. You can learn from this and then integrate what you want back to your solution.
Create a new blank page. Mine was page 17. You'll need to update references to "P17" with your page number if it's different. Disable the page level attribute Warn on Unsaved Changes to prevent prompts before the redirect to Google.
Add a new HTML region to the page.
Add a new item to the region. Set Name to P17_FIRST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_LAST_NAME and leave the default Type of Text Field.
Add a new item to the region. Set Name to P17_RESULT, Type to Hidden, and Value Protected to No. This item will be used to transfer messages from the server to the client via Ajax.
Add a button to the region. Set Name to RUN_PROCESS and Action to Defined by Dynamic Action.
Create a new Dynamic Action that fires when the button is clicked. The easiest way to do this is to right-click the button and select Create Dynamic Action. Set the Name to RUN_PROCESS clicked.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute PL/SQL Code and copy-paste the following code into the PL/SQL Code attribute.
declare
l_result_obj json_object_t := json_object_t();
l_errors_arr json_array_t := json_array_t();
l_error_obj json_object_t;
begin
if :P17_FIRST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_FIRST_NAME');
l_error_obj.put('message', 'First Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if :P17_LAST_NAME is null
then
l_error_obj := json_object_t();
l_error_obj.put('pageItem', 'P17_LAST_NAME');
l_error_obj.put('message', 'Last Name is required.');
l_errors_arr.append(l_error_obj);
end if;
if l_errors_arr.get_size() > 0
then
l_result_obj.put('status', 'error');
l_result_obj.put('errors', l_errors_arr);
:P17_RESULT := l_result_obj.to_string();
return;
end if;
null; -- do "success" processing here
l_result_obj.put('status', 'success');
l_result_obj.put('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
:P17_RESULT := l_result_obj.to_string();
end;
As you can see, the validations are now being done inside the process. The PL/SQL code is making use of the JSON types introduced with Oracle 12.2. If you're on an older version of the database, you can adapt the code to use APEX_JSON instead.
While still in the Execute PL/SQL Code action, set Items to Submit to P17_FIRST_NAME,P17_LAST_NAME and Items to Return to P17_RESULT. This is how you can transfer values from the page into session state before the process executes and then back to the page after the process finishes executing.
Create a new Dynamic Action that fires on the Change event of P17_RESULT. The easiest way to do this is to right-click the item and select Create Dynamic Action. Set the Name to P17_RESULT changed.
Select the Show action that was created by default for the Dynamic Action. Set Action to Execute JavaScript Code and copy-paste the following code into the Code attribute.
var result = JSON.parse($v('P17_RESULT'));
apex.message.clearErrors();
if (result.status === 'error') {
for (var idx = 0; idx < result.errors.length; idx++) {
result.errors[idx].type = 'error';
result.errors[idx].location = ['page', 'inline'];
result.errors[idx].unsafe = false;
}
apex.message.showErrors(result.errors);
} else if (result.status === 'success') {
apex.message.alert(result.message, function(){
apex.navigation.redirect('https://google.com');
});
}
The JavaScript code takes the result from the process and either displays error messages or an alert. I'm using apex.message.alert instead of apex.message.showPageSuccess because the former supports a callback when the message is dismissed. When the message is dismissed, apex.navigation.redirect takes the user to Google.
Here's what it should look like in the end:
I hope there's enough information here for you to understand what's going on. Let me know if you have any questions. You'll find the documentation for apex.navigation and apex.message here: https://apex.oracle.com/jsapi
P.S. Here's an example of what the PL/SQL code would look like using APEX_JSON.
declare
l_error_count pls_integer := 0;
l_result_obj clob;
begin
apex_json.initialize_clob_output;
apex_json.open_object();
apex_json.open_array('errors');
if :P17_FIRST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_FIRST_NAME');
apex_json.write('message', 'First Name is required.');
apex_json.close_object();
end if;
if :P17_LAST_NAME is null
then
l_error_count := l_error_count + 1;
apex_json.open_object();
apex_json.write('pageItem', 'P17_LAST_NAME');
apex_json.write('message', 'Last Name is required.');
apex_json.close_object();
end if;
apex_json.close_array();
if l_error_count > 0
then
apex_json.write('status', 'error');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
return;
end if;
null; -- do "success" processing here
apex_json.write('status', 'success');
apex_json.write('message', 'Hi ' || :P17_LAST_NAME || ' ' || :P17_LAST_NAME ||
'! You will now be redirected to Google.');
apex_json.close_object();
:P17_RESULT := apex_json.get_clob_output();
apex_json.free_output;
end;
Is it possible to delete files from this folder and how?
Currently i have this which doesnt work
[UninstallDelete]
Type: files; Name: "{userappdata}\Roaming\Myapp\*";
Type: files; Name: "{commonappdata}\Roaming\Myapp\*";
Type: files; Name: "{app}\*.*";
[Code]
/////////////////////////////////////////////////////////////////////
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
/////////////////////////////////////////////////////////////////////
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
/////////////////////////////////////////////////////////////////////
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
// Return Values:
// 1 - uninstall string is empty
// 2 - error executing the UnInstallString
// 3 - successfully executed the UnInstallString
// default return value
Result := 0;
// get the uninstall string of the old app
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
/////////////////////////////////////////////////////////////////////
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
end;
While Inno can remove files from the profile of the user running the uninstaller, it can not touch any other user's profile.
If the user trying to run the uninstaller is a limited user, it will ask for the admin details and so any {user...} constants will resolve to the admin user, NOT the limited user.
Your best option in this case is it leave any of the user's configuration and data in case they want to reinstall or have roaming profiles. Also note that in your code above, the old setup is removed during the upgrade which will trigger the "remove all the user's data" option. I'm sure that's not what you want...