From 5d2994bd4080740a81b39307b67f7f0d34e15e73 Mon Sep 17 00:00:00 2001 From: Jan Kvetina Date: Fri, 11 Mar 2022 21:55:43 +0100 Subject: [PATCH] Send message to user via AJAX ping, for example when BG job finishes --- apex/f770/application/pages/page_00910.sql | 5 +- .../logic/application_processes/ajax_ping.sql | 26 ++++ apex/f770/install.sql | 1 + packages/app_actions.spec.sql | 34 +++++ packages/app_actions.sql | 116 ++++++++++++++++++ tables/user_messages.sql | 37 ++++++ 6 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 apex/f770/application/shared_components/logic/application_processes/ajax_ping.sql create mode 100644 tables/user_messages.sql diff --git a/apex/f770/application/pages/page_00910.sql b/apex/f770/application/pages/page_00910.sql index a293b97..cfe011a 100644 --- a/apex/f770/application/pages/page_00910.sql +++ b/apex/f770/application/pages/page_00910.sql @@ -23,7 +23,7 @@ wwv_flow_api.create_page( ,p_required_role=>wwv_flow_api.id(9556407311505078) ,p_page_comment=>'Navigation setup page' ,p_last_updated_by=>'DEV' -,p_last_upd_yyyymmddhh24miss=>'20220306094513' +,p_last_upd_yyyymmddhh24miss=>'20220311201303' ); wwv_flow_api.create_page_plug( p_id=>wwv_flow_api.id(24141119524306145) @@ -3300,8 +3300,7 @@ wwv_flow_api.create_page_process( ,p_process_sql_clob=>wwv_flow_string.join(wwv_flow_t_varchar2( 'app.log_action(''PUBLISH_CHANGES'');', '--', -'DBMS_MVIEW.REFRESH(''NAV_AVAILABILITY_MVW'', ''C'', parallelism => 2);', -'DBMS_MVIEW.REFRESH(''NAV_OVERVIEW_MVW'', ''C'', parallelism => 2);', +'app_actions.refresh_nav_views();', '--', 'app.log_success();', '')) diff --git a/apex/f770/application/shared_components/logic/application_processes/ajax_ping.sql b/apex/f770/application/shared_components/logic/application_processes/ajax_ping.sql new file mode 100644 index 0000000..9ab9502 --- /dev/null +++ b/apex/f770/application/shared_components/logic/application_processes/ajax_ping.sql @@ -0,0 +1,26 @@ +prompt --application/shared_components/logic/application_processes/ajax_ping +begin +-- Manifest +-- APPLICATION PROCESS: AJAX_PING +-- Manifest End +wwv_flow_api.component_begin ( + p_version_yyyy_mm_dd=>'2021.04.15' +,p_release=>'21.1.7' +,p_default_workspace_id=>9014660246496943 +,p_default_application_id=>770 +,p_default_id_offset=>0 +,p_default_owner=>'CORE' +); +wwv_flow_api.create_flow_process( + p_id=>wwv_flow_api.id(35698122384645663) +,p_process_sequence=>10 +,p_process_point=>'ON_DEMAND' +,p_process_type=>'NATIVE_PLSQL' +,p_process_name=>'AJAX_PING' +,p_process_sql_clob=>'app_actions.ajax_ping();' +,p_process_clob_language=>'PLSQL' +,p_security_scheme=>'MUST_NOT_BE_PUBLIC_USER' +); +wwv_flow_api.component_end; +end; +/ diff --git a/apex/f770/install.sql b/apex/f770/install.sql index adba183..411e32e 100644 --- a/apex/f770/install.sql +++ b/apex/f770/install.sql @@ -17,6 +17,7 @@ prompt --install @@application/shared_components/logic/application_processes/init_translations.sql @@application/shared_components/logic/application_processes/init_globals.sql @@application/shared_components/logic/application_processes/init_filters.sql +@@application/shared_components/logic/application_processes/ajax_ping.sql @@application/shared_components/logic/application_items/g_curr_owner.sql @@application/shared_components/logic/application_items/g_footer.sql @@application/shared_components/logic/application_items/g_today.sql diff --git a/packages/app_actions.spec.sql b/packages/app_actions.spec.sql index 3cda48e..adbfaa4 100644 --- a/packages/app_actions.spec.sql +++ b/packages/app_actions.spec.sql @@ -97,6 +97,19 @@ CREATE OR REPLACE PACKAGE app_actions AS + -- + -- Refresh navigation MVW in a background job and inform user + -- + PROCEDURE refresh_nav_views ( + in_log_id logs.log_id%TYPE, + in_user_id logs.user_id%TYPE, + in_app_id logs.app_id%TYPE + ); + -- + PROCEDURE refresh_nav_views; + + + -- -- Save changes on Navigation page -- @@ -475,5 +488,26 @@ CREATE OR REPLACE PACKAGE app_actions AS in_value_hu translated_messages_overview.value_hu%TYPE ); + + + -- + -- Ping procedure to keep communicate with users via AJAX + -- + PROCEDURE ajax_ping; + + + + -- + -- Send message to user + -- + PROCEDURE send_message ( + in_user_id user_messages.user_id%TYPE, + in_message user_messages.message_payload%TYPE, + in_type user_messages.message_type%TYPE := NULL, + in_session_id user_messages.session_id%TYPE := NULL, + in_app_id user_messages.app_id%TYPE := NULL, + in_message_id user_messages.message_id%TYPE := NULL + ); + END; / diff --git a/packages/app_actions.sql b/packages/app_actions.sql index 7c9e26e..a58f2aa 100644 --- a/packages/app_actions.sql +++ b/packages/app_actions.sql @@ -220,6 +220,48 @@ CREATE OR REPLACE PACKAGE BODY app_actions AS + PROCEDURE refresh_nav_views ( + in_log_id logs.log_id%TYPE, + in_user_id logs.user_id%TYPE, + in_app_id logs.app_id%TYPE + ) + AS + BEGIN + DBMS_MVIEW.REFRESH('NAV_OVERVIEW_MVW', 'C', parallelism => 2); + DBMS_MVIEW.REFRESH('NAV_AVAILABILITY_MVW', 'C', parallelism => 2); + -- + app_actions.send_message ( + in_app_id => in_app_id, + in_user_id => in_user_id, + in_message => 'Materialized views refreshed' + + ); + -- + app.log_success(TO_CHAR(in_log_id)); + END; + + + + PROCEDURE refresh_nav_views + AS + v_log_id logs.log_id%TYPE; + v_query VARCHAR2(32767); + BEGIN + v_log_id := app.log_module(); + -- + app.create_job ( + in_job_name => 'RECALC_MVW_NAV', + in_statement => 'app_actions.refresh_nav_views(' || v_log_id || ', ''' || app.get_user_id() || ''', ' || app.get_app_id() || ');' + ); + EXCEPTION + WHEN app.app_exception THEN + RAISE; + WHEN OTHERS THEN + app.raise_error(); + END; + + + PROCEDURE save_nav_overview ( in_action CHAR, in_app_id navigation.app_id%TYPE, @@ -1744,5 +1786,79 @@ CREATE OR REPLACE PACKAGE BODY app_actions AS app.raise_error(); END; + + + PROCEDURE ajax_ping + AS + BEGIN + APEX_JSON.OPEN_OBJECT(); + -- + -- APEX_APPLICATION.G_X01, APEX_APPLICATION.G_X02, APEX_APPLICATION.G_X03 + -- + APEX_JSON.WRITE('status', 'SUCCESS'); + -- + FOR c IN ( + SELECT m.* + FROM user_messages m + WHERE m.app_id = app.get_app_id() + AND m.user_id = app.get_user_id() + AND (m.session_id = app.get_session_id() OR m.session_id IS NULL) + AND m.delivered_at IS NULL + ORDER BY m.created_at DESC + FETCH FIRST 1 ROWS ONLY + ) LOOP + APEX_JSON.WRITE('message', c.message_payload); + APEX_JSON.WRITE('type', c.message_type); + -- + UPDATE user_messages m + SET m.delivered_at = SYSDATE + WHERE m.app_id = c.app_id + AND m.user_id = c.user_id + AND m.message_id = c.message_id; + END LOOP; + -- + APEX_JSON.CLOSE_OBJECT(); + EXCEPTION + WHEN app.app_exception THEN + RAISE; + WHEN OTHERS THEN + app.raise_error(); + END; + + + + PROCEDURE send_message ( + in_user_id user_messages.user_id%TYPE, + in_message user_messages.message_payload%TYPE, + in_type user_messages.message_type%TYPE := NULL, + in_session_id user_messages.session_id%TYPE := NULL, + in_app_id user_messages.app_id%TYPE := NULL, + in_message_id user_messages.message_id%TYPE := NULL + ) + AS + v_log_id logs.log_id%TYPE; + BEGIN + v_log_id := app.log_module(); + -- + INSERT INTO user_messages (app_id, user_id, message_id, message_type, message_payload, session_id, created_at, created_by) + VALUES ( + COALESCE(in_app_id, app.get_app_id()), + in_user_id, + COALESCE(in_message_id, log_id.NEXTVAL), + COALESCE(in_type, 'SUCCESS'), + in_message, + in_session_id, + SYSDATE, + app.get_user_id() + ); + -- + app.log_success(); + EXCEPTION + WHEN app.app_exception THEN + RAISE; + WHEN OTHERS THEN + app.raise_error(); + END; + END; / diff --git a/tables/user_messages.sql b/tables/user_messages.sql new file mode 100644 index 0000000..7786a11 --- /dev/null +++ b/tables/user_messages.sql @@ -0,0 +1,37 @@ +--DROP TABLE user_messages PURGE; +CREATE TABLE user_messages ( + app_id NUMBER(4) CONSTRAINT nn_user_messages_app_id NOT NULL, + user_id VARCHAR2(30) CONSTRAINT nn_user_messages_user_id NOT NULL, + message_id INTEGER CONSTRAINT nn_user_messages_message_id NOT NULL, -- log_id + message_type VARCHAR2(16), + message_payload VARCHAR2(2000), + session_id INTEGER, + -- + created_by VARCHAR2(30), + created_at DATE, + delivered_at DATE, + -- + CONSTRAINT pk_user_messages + PRIMARY KEY (app_id, user_id, message_id), + -- + CONSTRAINT fk_user_messages_app_id + FOREIGN KEY (app_id) + REFERENCES apps (app_id), + -- + CONSTRAINT fk_user_messages_user_id + FOREIGN KEY (user_id) + REFERENCES users (user_id) + DEFERRABLE INITIALLY DEFERRED +) +STORAGE (BUFFER_POOL KEEP); +-- +COMMENT ON TABLE user_messages IS '[CORE] Messages for users'; +-- +COMMENT ON COLUMN user_messages.app_id IS 'APEX application ID'; +COMMENT ON COLUMN user_messages.user_id IS 'User ID from USERS table'; +COMMENT ON COLUMN user_messages.message_id IS 'Message id'; +COMMENT ON COLUMN user_messages.message_type IS 'Message type'; +COMMENT ON COLUMN user_messages.message_payload IS 'Message itself'; +COMMENT ON COLUMN user_messages.session_id IS 'Session id'; +COMMENT ON COLUMN user_messages.delivered_at IS 'Stamp of delivery'; +