From 00cdd7ca18321f1e137aa3b85aa530b6a23b9e5d Mon Sep 17 00:00:00 2001 From: xbgmsharp Date: Fri, 2 Dec 2022 11:22:28 +0100 Subject: [PATCH] Refactor web user notification Add new cron job cron_new_notification Add public.cron_process_new_notification_fn function Add public.process_notification_queue_fn function Update messages template table, align cron name with template notification name --- initdb/02_2_signalk_cron.sql | 37 +++++++++++++-- initdb/02_3_1_signalk_public_tables.sql | 21 +++++---- initdb/02_3_2_signalk_public_functions.sql | 53 ++++++++++++++++++++++ initdb/04pgcron.sql | 11 +++-- 4 files changed, 108 insertions(+), 14 deletions(-) diff --git a/initdb/02_2_signalk_cron.sql b/initdb/02_2_signalk_cron.sql index 8cdb889..56f36cc 100644 --- a/initdb/02_2_signalk_cron.sql +++ b/initdb/02_2_signalk_cron.sql @@ -154,7 +154,7 @@ begin END; $$ language plpgsql; -- Description -COMMENT ON FUNCTION +COMMENT ON FUNCTION public.cron_process_monitor_offline_fn IS 'init by pg_cron to monitor offline pending notification, if so perform send_email o send_pushover base on user preferences'; @@ -207,7 +207,7 @@ begin END; $$ language plpgsql; -- Description -COMMENT ON FUNCTION +COMMENT ON FUNCTION public.cron_process_monitor_online_fn IS 'init by pg_cron to monitor back online pending notification, if so perform send_email or send_pushover base on user preferences'; @@ -236,7 +236,7 @@ begin END; $$ language plpgsql; -- Description -COMMENT ON FUNCTION +COMMENT ON FUNCTION public.cron_process_new_account_fn IS 'init by pg_cron to check for new account pending update, if so perform process_account_queue_fn'; @@ -298,6 +298,37 @@ COMMENT ON FUNCTION public.cron_process_new_vessel_fn IS 'init by pg_cron to check for new vessel pending update, if so perform process_vessel_queue_fn'; +-- CRON for new event notification +CREATE FUNCTION cron_process_new_notification_fn() RETURNS void AS $$ +declare + process_rec record; +begin + -- Check for new event notification pending update + RAISE NOTICE 'cron_process_new_notification_fn'; + FOR process_rec in + SELECT * FROM process_queue + WHERE + (channel = 'new_account' OR channel = 'new_vessel' OR channel = 'email_otp') + and processed is null + order by stored asc + LOOP + RAISE NOTICE '-> cron_process_new_notification_fn for [%]', process_rec.payload; + -- process_notification_queue + PERFORM process_notification_queue_fn(process_rec.payload::TEXT, process_rec.channel::TEXT); + -- update process_queue entry as processed + UPDATE process_queue + SET + processed = NOW() + WHERE id = process_rec.id; + RAISE NOTICE '-> cron_process_new_notification_fn updated process_queue table [%]', process_rec.id; + END LOOP; +END; +$$ language plpgsql; +-- Description +COMMENT ON FUNCTION + public.cron_process_new_notification_fn + IS 'init by pg_cron to check for new event pending notifications, if so perform process_notification_queue_fn'; + -- CRON for Vacuum database CREATE FUNCTION cron_vaccum_fn() RETURNS void AS $$ declare diff --git a/initdb/02_3_1_signalk_public_tables.sql b/initdb/02_3_1_signalk_public_tables.sql index dad9132..0d774ce 100644 --- a/initdb/02_3_1_signalk_public_tables.sql +++ b/initdb/02_3_1_signalk_public_tables.sql @@ -55,12 +55,12 @@ INSERT INTO email_templates VALUES E'Hello __RECIPIENT__,\n\nWe just wanted to let you know that you have a new entry on openplotter.cloud: "__LOGBOOK_NAME__"\r\n\r\nSee more details at __APP_URL__/log/__LOGBOOK_LINK__\n\nHappy sailing!\nThe PostgSail Team', 'New Logbook Entry', E'We just wanted to let you know that you have a new entry on openplotter.cloud: "__LOGBOOK_NAME__"\r\n\r\nSee more details at __APP_URL__/log/__LOGBOOK_LINK__\n\nHappy sailing!\nThe PostgSail Team'), -('user', +('new_account', 'Welcome', E'Hello __RECIPIENT__,\nCongratulations!\nYou successfully created an account.\nKeep in mind to register your vessel.\nHappy sailing!', 'Welcome', E'Hi!\nYou successfully created an account\nKeep in mind to register your vessel.\nHappy sailing!'), -('vessel', +('new_vessel', 'New vessel', E'Hi!\nHow are you?\n__BOAT__ is now linked to your account.', 'New vessel', @@ -80,16 +80,21 @@ INSERT INTO email_templates VALUES E'Hello __RECIPIENT__,\nCongratulations! You have just unlocked a new badge: __BADGE_NAME__\nSee more details at __APP_URL__/badges\nHappy sailing!\nThe PostgSail Team', 'New Badge!', E'Congratulations!\nYou have just unlocked a new badge: __BADGE_NAME__\nSee more details at __APP_URL__/badges\nHappy sailing!\nThe PostgSail Team'), -('pushover', +('pushover_valid', 'Pushover integration', - E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to pushover.\n\nThe PostgSail Team', + E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to Pushover.\n\nThe PostgSail Team', 'Pushover integration!', - E'Congratulations!\nYou have just connect your account to pushover.\n\nThe PostgSail Team'), + E'Congratulations!\nYou have just connect your account to Pushover.\n\nThe PostgSail Team'), ('email_otp', 'Email verification', E'Hello __RECIPIENT__,\nPlease active your account using the following code: __OTP_CODE__.\nThe code is valid 15 minutes.\nThe PostgSail Team', 'Email verification', E'Congratulations!\nPlease validate your account. Check your email!'), +('email_valid', + 'Email verified', + E'Hello __RECIPIENT__,\nCongratulations!\nYou successfully validate your account.\nThe PostgSail Team', + 'Email verified', + E'Hi!\nYou successfully validate your account.\nHappy sailing!'), ('telegram_otp', 'Telegram bot', E'Hello __RECIPIENT__,\nTo connect your account to a @postgsail_bot. Please type this verification code __OTP_CODE__ back to the bot.\nThe code is valid 15 minutes.\nThe PostgSail Team', @@ -97,9 +102,9 @@ INSERT INTO email_templates VALUES E'Congratulations!\nTo connect your account to a @postgsail_bot. Check your email!'), ('telegram_valid', 'Telegram bot', - E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to a @postgsail_bot.\n\nThe PostgSail Team', + E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to your vessel, @postgsail_bot.\n\nThe PostgSail Team', 'Telegram bot!', - E'Congratulations!\nYou have just connect your account to a @postgsail_bot.\n\nHappy sailing!\nThe PostgSail Team'); + E'Congratulations!\nYou have just connect your account to your vessel, @postgsail_bot.\n\nHappy sailing!\nThe PostgSail Team'); --------------------------------------------------------------------------- -- Queue handling @@ -142,7 +147,7 @@ $new_account_entry$ language plpgsql; create function new_account_otp_validation_entry_fn() returns trigger as $new_account_otp_validation_entry$ begin - insert into process_queue (channel, payload, stored) values ('new_account_otp', NEW.email, now()); + insert into process_queue (channel, payload, stored) values ('email_otp', NEW.email, now()); return NEW; END; $new_account_otp_validation_entry$ language plpgsql; diff --git a/initdb/02_3_2_signalk_public_functions.sql b/initdb/02_3_2_signalk_public_functions.sql index 7a72644..1fa6932 100644 --- a/initdb/02_3_2_signalk_public_functions.sql +++ b/initdb/02_3_2_signalk_public_functions.sql @@ -406,6 +406,59 @@ COMMENT ON FUNCTION public.process_account_otp_validation_queue_fn IS 'process new account otp validation notification'; +-- process new event notification +DROP FUNCTION IF EXISTS process_notification_queue_fn; +CREATE OR REPLACE FUNCTION process_notification_queue_fn(IN _email TEXT, IN message_type TEXT) RETURNS void +AS $process_notification_queue$ + DECLARE + account_rec record; + vessel_rec record; + user_settings jsonb := null; + otp_code text; + BEGIN + IF _email IS NULL OR _email = '' THEN + RAISE EXCEPTION 'Invalid email' + USING HINT = 'Unkown email'; + RETURN; + END IF; + SELECT * INTO account_rec + FROM auth.accounts + WHERE email = _email; + IF account_rec.email IS NULL OR account_rec.email = '' THEN + RAISE EXCEPTION 'Invalid email' + USING HINT = 'Unkown email'; + RETURN; + END IF; + + RAISE NOTICE '--> process_notification_queue_fn type [%] [%]', _email,message_type; + -- set user email variable + PERFORM set_config('user.email', account_rec.email, false); + -- Generate user_settings user settings + IF message_type = 'new_account' THEN + user_settings := '{"email": "' || account_rec.email || '", "recipient": "' || account_rec.first || '"}'; + ELSEIF message_type = 'new_vessel' THEN + -- Gather vessel data + SELECT * INTO vessel_rec + FROM auth.vessels + WHERE owner_email = _email; + IF vessel_rec.owner_email IS NULL OR vessel_rec.owner_email = '' THEN + RAISE EXCEPTION 'Invalid email' + USING HINT = 'Unkown email'; + RETURN; + END IF; + user_settings := '{"email": "' || vessel_rec.owner_email || '", "boat": "' || vessel_rec.name || '"}'; + ELSEIF message_type = 'email_otp' THEN + otp_code := api.generate_otp_fn(_email); + user_settings := '{"email": "' || account_rec.email || '", "recipient": "' || account_rec.first || '", "otp_code": "' || otp_code || '"}'; + END IF; + PERFORM send_notification_fn(message_type::TEXT, user_settings::JSONB); + END; +$process_notification_queue$ LANGUAGE plpgsql; +-- Description +COMMENT ON FUNCTION + public.process_notification_queue_fn + IS 'process new event type notification'; + -- process new vessel notification DROP FUNCTION IF EXISTS process_vessel_queue_fn; CREATE OR REPLACE FUNCTION process_vessel_queue_fn(IN _email TEXT) RETURNS void AS $process_vessel_queue$ diff --git a/initdb/04pgcron.sql b/initdb/04pgcron.sql index e9d88c3..d208bf8 100644 --- a/initdb/04pgcron.sql +++ b/initdb/04pgcron.sql @@ -31,17 +31,22 @@ SELECT cron.schedule('cron_monitor_online', '*/10 * * * *', 'select public.cron_ --UPDATE cron.job SET database = 'signalk' where jobname = 'cron_monitor_online'; -- Create a every 5 minute job cron_process_new_account_fn -SELECT cron.schedule('cron_new_account', '*/5 * * * *', 'select public.cron_process_new_account_fn()'); +--SELECT cron.schedule('cron_new_account', '*/5 * * * *', 'select public.cron_process_new_account_fn()'); --UPDATE cron.job SET database = 'signalk' where jobname = 'cron_new_account'; -- Create a every 5 minute job cron_process_new_vessel_fn -SELECT cron.schedule('cron_new_vessel', '*/5 * * * *', 'select public.cron_process_new_vessel_fn()'); +--SELECT cron.schedule('cron_new_vessel', '*/5 * * * *', 'select public.cron_process_new_vessel_fn()'); --UPDATE cron.job SET database = 'signalk' where jobname = 'cron_new_vessel'; -- Create a every 6 minute job cron_process_new_account_otp_validation_queue_fn, delay from cron_new_account -SELECT cron.schedule('cron_new_account_otp', '*/6 * * * *', 'select public.cron_process_new_account_otp_validation_fn()'); +--SELECT cron.schedule('cron_new_account_otp', '*/6 * * * *', 'select public.cron_process_new_account_otp_validation_fn()'); --UPDATE cron.job SET database = 'signalk' where jobname = 'cron_new_account_otp'; +-- Notification +-- Create a every 1 minute job cron_process_new_notification_queue_fn, new_account, new_vessel, _new_account_otp +SELECT cron.schedule('cron_new_notification', '*/6 * * * *', 'select public.cron_process_new_notification_fn()'); +--UPDATE cron.job SET database = 'signalk' where jobname = 'cron_new_notification'; + -- Maintenance -- Vacuum database at “At 01:01 on Sunday.” SELECT cron.schedule('cron_vacumm', '1 1 * * 0', 'select public.cron_vaccum_fn()');