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 ;)
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.
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;
I have a RESET_PSWD button on a Form that calls a dynamic action with 4 true actions defined.
Confirm Action
Execute Server-side Code - PL/SQL procedure to generate new temp pswd
Execute Server-side Code - PL/SQL procedure to generate modal url using APEX_PAGE.GET_URL
Execute JavaScript Code - use url from step 3 to open modal
The goal of the DA is to generate a Temp Password, build a URL to the modal (passing in the new Temp Password from Step 2), and then navigate to the modal. Between Step 2 and Step 3 the value in P7_TEMP_PSWD is getting truncated due to special characters not being url encoded correctly between the request calls.
-- package procedure to get & set url for confirmation modal (Step 3)
PROCEDURE get_feedback_url (
p_username VARCHAR2,
p_temp_pswd VARCHAR2
) IS
vcPswdEncoded VARCHAR2(1000);
vcURL VARCHAR2(1000);
vcValueList VARCHAR2(1000);
BEGIN
vcPswdEncoded := APEX_UTIL.URL_ENCODE(p_temp_pswd);
vcValueList := p_username ||','|| vcPswdEncoded;
vcURL := APEX_PAGE.GET_URL(p_page => '12',
p_items => 'P12_USERNAME,P12_TEMP_PSWD',
p_values => vcValueList,
p_plain_url => TRUE);
APEX_UTIL.SET_SESSION_STATE('P7_FEEDBACK_URL', vcURL);
EXCEPTION
WHEN OTHERS THEN
csa.rsn_logger.log_error(p_rsn_app => 'RSNUM',
p_app_loc => 'rsnum_user.get_feedback_url',
p_log_msg => SQLERRM);
END;
I am trying to url encode the temp pswd before building the url, but I am getting the following results:
The value after using APEX_UTIL.ENCODE_URL is what I want, but it seems like APEX_PAGE.GET_URL is also encoding the values so '%' is encoded again. Is there a way to opt out of GET_URL doing this? The reason why I am using ENCODE_URL in the first place is because APEX does was not encode '#' (and a few other characters) by default and that was causing me problems originally.
Wish there was a better way to do this, but figured out a working solution (will need to test edge cases, but seems to work). I created a Before Header computation on the modal page with the following expression:
UTL_URL.UNESCAPE(:P12_TEMP_PSWD)
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;
I have an Interactive report in Apex 5, and each time the page load, I want it to look exactly as it was shown the first time I ran it, with default settings.
The problem is that if the user applies any filter, or hide columns, the next time the page loads, the report remembers that configuration.
I tried to use the APEX_IR.RESET_REPORT procedure undocumented here:
https://docs.oracle.com/database/121/AEAPI/apex_ir.htm#BABEJAFB
but it either doesn't works, or only undoes the last change, or needs many runs to actually work.
I tried a dynamic action at page load with this code:
DECLARE
v_region_id APEX_APPLICATION_PAGE_REGIONS.REGION_ID%TYPE;
BEGIN
SELECT region_id INTO v_region_id
FROM APEX_APPLICATION_PAGE_REGIONS
WHERE application_id = :APP_ID
AND page_id = :APP_PAGE_ID
AND static_id = 'Images_Report';
APEX_IR.RESET_REPORT(
P_page_id => :APP_PAGE_ID,
P_region_id => v_region_id,
p_report_id => null
);
END;
And I also tried this code
DECLARE
v_region_id APEX_APPLICATION_PAGE_REGIONS.REGION_ID%TYPE;
BEGIN
SELECT region_id INTO v_region_id
FROM APEX_APPLICATION_PAGE_REGIONS
WHERE application_id = :APP_ID
AND page_id = :APP_PAGE_ID
AND static_id = 'Images_Report';
APEX_IR.RESET_REPORT(
P_page_id => :APP_PAGE_ID,
P_region_id => v_region_id,
p_report_id => APEX_IR.GET_LAST_VIEWED_REPORT_ID(
p_page_id => :APP_PAGE_ID,
p_region_id => v_region_id
)
);
END;
I expect the report to look as in default state (on first run), every time I load the page.
Instead the report shows the last state, even if the user logs out, logs in and restarts the application.
Send RIR as the clear cache parameter in your URL
https://docs.oracle.com/database/apex-5.1/HTMDB/linking-to-interactive-reports.htm#GUID-B917CEB3-A0B9-414B-A90A-7B44DD15EA67
URL would look like
f?p=102:94:6722612001859::NO:RIR::
https://docs.oracle.com/database/apex-5.1/HTMDB/understanding-url-syntax.htm#HTMDB03019
The documentation states this regarding the apex_ir.reset_report procedure
This procedure should only be used in page submit processes.
Which could be why you had trouble