17 Commits

Author SHA1 Message Date
xbgmsharp
cc67a3b37d Release v0.1.0 2023-06-23 11:03:16 +02:00
xbgmsharp
64ecbfc698 Fix typo 2023-06-22 23:28:45 +02:00
xbgmsharp
b19eeed59a Update badges, renew badge 2023-06-22 23:28:05 +02:00
xbgmsharp
8f5cd4237d dd new API endpoint, api.vessel_details_fn(), extend additionals vessels properties 2023-06-22 23:26:44 +02:00
xbgmsharp
7b3a1451bb Update templates messages
Add iso3166 country list
Link MMSI MID Codes with iso3166 country list
2023-06-21 15:49:10 +02:00
xbgmsharp
a2cdd8ddfe Add badges support 2023-06-20 15:24:47 +02:00
xbgmsharp
7a04026e67 Marked old function as deprecated 2023-06-20 09:05:27 +02:00
xbgmsharp
fab496ea3d Add web frontend container and update telegram container env 2023-06-07 12:22:20 +02:00
xbgmsharp
4f31831c94 Update prepare jwt auth with user_id 2023-06-07 12:20:40 +02:00
xbgmsharp
300e4bee48 Update debug output 2023-06-07 12:19:15 +02:00
xbgmsharp
99e258c974 Update Send notification telegram SQL requets 2023-05-25 16:37:01 +02:00
xbgmsharp
970c85c11e Update reverse geoip python function
Update parsing geosjon python function
2023-05-25 16:35:39 +02:00
xbgmsharp
bbf4426f55 Update OTP, add support for telegram 2023-05-25 16:34:35 +02:00
xbgmsharp
a8620f4b4c Update api_anonymous function persmision to support telegram 2023-05-25 16:28:59 +02:00
xbgmsharp
15accaa4cb Update api.metadata version fields to type TEXT
Update debug output formating
Update SQL view statements, Make SQL error proof with REPLACE statement
2023-05-25 16:26:19 +02:00
xbgmsharp
8d382b48ac Add telegram bot 2023-05-22 11:34:17 +02:00
xbgmsharp
2983f149ad Update .env sample for Telegram-bot 2023-05-17 16:37:31 +02:00
12 changed files with 1091 additions and 485 deletions

View File

@@ -12,8 +12,9 @@ PGSAIL_EMAIL_SERVER=localhost
#PGSAIL_EMAIL_PASS= Comment if not use #PGSAIL_EMAIL_PASS= Comment if not use
#PGSAIL_PUSHOVER_APP_TOKEN= Comment if not use #PGSAIL_PUSHOVER_APP_TOKEN= Comment if not use
#PGSAIL_PUSHOVER_APP_URL= Comment if not use #PGSAIL_PUSHOVER_APP_URL= Comment if not use
#PGSAIL_PGSAIL_TELEGRAM_BOT_TOKEN= Comment if not use #PGSAIL_TELEGRAM_BOT_TOKEN= Comment if not use
PGSAIL_APP_URL=http://localhost PGSAIL_APP_URL=http://localhost
PGSAIL_API_URL=http://localhost
# POSTGREST ENV Settings # POSTGREST ENV Settings
PGRST_DB_URI=postgres://authenticator:${PGSAIL_AUTHENTICATOR_PASSWORD}@127.0.0.1:5432/signalk PGRST_DB_URI=postgres://authenticator:${PGSAIL_AUTHENTICATOR_PASSWORD}@127.0.0.1:5432/signalk
PGRST_JWT_SECRET=_at_least_32__char__long__random PGRST_JWT_SECRET=_at_least_32__char__long__random

View File

@@ -79,5 +79,42 @@ services:
# retries: 5 # retries: 5
# start_period: 100s # start_period: 100s
telegram:
image: xbgmsharp/postgsail-telegram-bot
container_name: telegram
restart: unless-stopped
volumes:
- /etc/resolv.conf:/etc/resolv.conf:ro
ports:
- "3005:8080"
network_mode: "host"
env_file: .env
environment:
- BOT_TOKEN=${PGSAIL_TELEGRAM_BOT_TOKEN}
- PGSAIL_URL=${PGSAIL_API_URL}
depends_on:
- db
- api
logging:
options:
max-size: 10m
web:
image: xbgmsharp/postgsail-vuestic
container_name: web
restart: unless-stopped
volumes:
- /etc/resolv.conf:/etc/resolv.conf:ro
ports:
- "3006:8080"
network_mode: "host"
env_file: .env
depends_on:
- db
- api
logging:
options:
max-size: 10m
volumes: volumes:
data: {} data: {}

View File

@@ -89,8 +89,8 @@ CREATE TABLE IF NOT EXISTS api.metadata(
beam DOUBLE PRECISION NULL, beam DOUBLE PRECISION NULL,
height DOUBLE PRECISION NULL, height DOUBLE PRECISION NULL,
ship_type NUMERIC NULL, ship_type NUMERIC NULL,
plugin_version VARCHAR(10) NOT NULL, plugin_version TEXT NOT NULL,
signalk_version VARCHAR(10) NOT NULL, signalk_version TEXT NOT NULL,
time TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- should be rename to last_update !? time TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- should be rename to last_update !?
active BOOLEAN DEFAULT True, -- trigger monitor online/offline active BOOLEAN DEFAULT True, -- trigger monitor online/offline
-- vessel_id link auth.vessels with api.metadata -- vessel_id link auth.vessels with api.metadata
@@ -350,7 +350,7 @@ DROP FUNCTION IF EXISTS metadata_notification_trigger_fn;
CREATE FUNCTION metadata_notification_trigger_fn() RETURNS trigger AS $metadata_notification$ CREATE FUNCTION metadata_notification_trigger_fn() RETURNS trigger AS $metadata_notification$
DECLARE DECLARE
BEGIN BEGIN
RAISE NOTICE 'metadata_notification_trigger_fn'; RAISE NOTICE 'metadata_notification_trigger_fn [%]', NEW;
INSERT INTO process_queue (channel, payload, stored) INSERT INTO process_queue (channel, payload, stored)
VALUES ('monitoring_online', NEW.id, now()); VALUES ('monitoring_online', NEW.id, now());
RETURN NULL; RETURN NULL;
@@ -1035,7 +1035,7 @@ COMMENT ON VIEW
-- Stays web view -- Stays web view
-- TODO group by month -- TODO group by month
DROP VIEW IF EXISTS api.stays_view; DROP VIEW IF EXISTS api.stays_view;
CREATE VIEW api.stays_view WITH (security_invoker=true,security_barrier=true) AS CREATE OR REPLACE VIEW api.stays_view WITH (security_invoker=true,security_barrier=true) AS
SELECT s.id, SELECT s.id,
concat( concat(
extract(DAYS FROM (s.departed-s.arrived)::interval), extract(DAYS FROM (s.departed-s.arrived)::interval),
@@ -1068,7 +1068,7 @@ COMMENT ON VIEW
IS 'Stays web view'; IS 'Stays web view';
DROP VIEW IF EXISTS api.stay_view; DROP VIEW IF EXISTS api.stay_view;
CREATE VIEW api.stay_view WITH (security_invoker=true,security_barrier=true) AS CREATE OR REPLACE VIEW api.stay_view WITH (security_invoker=true,security_barrier=true) AS
SELECT s.id, SELECT s.id,
concat( concat(
extract(DAYS FROM (s.departed-s.arrived)::interval), extract(DAYS FROM (s.departed-s.arrived)::interval),
@@ -1180,7 +1180,7 @@ COMMENT ON VIEW
----> select sum(l.duration) as "Total Time Underway" from api.logbook l; ----> select sum(l.duration) as "Total Time Underway" from api.logbook l;
-- Longest Nonstop Sail from logbook, eg longest trip duration and distance -- Longest Nonstop Sail from logbook, eg longest trip duration and distance
----> select max(l.duration),max(l.distance) from api.logbook l; ----> select max(l.duration),max(l.distance) from api.logbook l;
CREATE VIEW api.stats_logs_view WITH (security_invoker=true,security_barrier=true) AS -- TODO CREATE OR REPLACE VIEW api.stats_logs_view WITH (security_invoker=true,security_barrier=true) AS -- TODO
WITH WITH
meta AS ( meta AS (
SELECT m.name FROM api.metadata m ), SELECT m.name FROM api.metadata m ),
@@ -1219,7 +1219,7 @@ COMMENT ON VIEW
----> select sum(m.stay_duration) as "Time Spent Away" from api.moorages m where home_flag is false; ----> select sum(m.stay_duration) as "Time Spent Away" from api.moorages m where home_flag is false;
-- Time Spent Away order by, group by stay_code (Dock, Anchor, Mooring Buoys, Unclassified) -- Time Spent Away order by, group by stay_code (Dock, Anchor, Mooring Buoys, Unclassified)
----> select sa.description,sum(m.stay_duration) as "Time Spent Away" from api.moorages m, api.stays_at sa where home_flag is false AND m.stay_code = sa.stay_code group by m.stay_code,sa.description order by m.stay_code; ----> select sa.description,sum(m.stay_duration) as "Time Spent Away" from api.moorages m, api.stays_at sa where home_flag is false AND m.stay_code = sa.stay_code group by m.stay_code,sa.description order by m.stay_code;
CREATE VIEW api.stats_moorages_view WITH (security_invoker=true,security_barrier=true) AS -- TODO CREATE OR REPLACE VIEW api.stats_moorages_view WITH (security_invoker=true,security_barrier=true) AS -- TODO
WITH WITH
home_ports AS ( home_ports AS (
select count(*) as home_ports from api.moorages m where home_flag is true select count(*) as home_ports from api.moorages m where home_flag is true
@@ -1243,7 +1243,7 @@ COMMENT ON VIEW
api.stats_moorages_view api.stats_moorages_view
IS 'Statistics Moorages web view'; IS 'Statistics Moorages web view';
CREATE VIEW api.stats_moorages_away_view WITH (security_invoker=true,security_barrier=true) AS -- TODO CREATE OR REPLACE VIEW api.stats_moorages_away_view WITH (security_invoker=true,security_barrier=true) AS -- TODO
SELECT sa.description,sum(m.stay_duration) as time_spent_away_by SELECT sa.description,sum(m.stay_duration) as time_spent_away_by
FROM api.moorages m, api.stays_at sa FROM api.moorages m, api.stays_at sa
WHERE home_flag IS false WHERE home_flag IS false
@@ -1269,7 +1269,8 @@ COMMENT ON VIEW
-- IS 'Statistics Moorages Time Spent Away web view'; -- IS 'Statistics Moorages Time Spent Away web view';
-- View main monitoring for web app -- View main monitoring for web app
CREATE VIEW api.monitoring_view WITH (security_invoker=true,security_barrier=true) AS DROP VIEW IF EXISTS api.monitoring_view;
CREATE OR REPLACE VIEW api.monitoring_view WITH (security_invoker=true,security_barrier=true) AS
SELECT SELECT
time AS "time", time AS "time",
(NOW() AT TIME ZONE 'UTC' - time) > INTERVAL '70 MINUTES' as offline, (NOW() AT TIME ZONE 'UTC' - time) > INTERVAL '70 MINUTES' as offline,
@@ -1282,6 +1283,8 @@ CREATE VIEW api.monitoring_view WITH (security_invoker=true,security_barrier=tru
metrics-> 'environment.outside.humidity' AS outsideHumidity, metrics-> 'environment.outside.humidity' AS outsideHumidity,
metrics-> 'environment.outside.pressure' AS outsidePressure, metrics-> 'environment.outside.pressure' AS outsidePressure,
metrics-> 'environment.inside.pressure' AS insidePressure, metrics-> 'environment.inside.pressure' AS insidePressure,
metrics-> 'electrical.batteries.House.capacity.stateOfCharge' AS batteryCharge,
metrics-> 'electrical.batteries.House.voltage' AS batteryVoltage,
jsonb_build_object( jsonb_build_object(
'type', 'Feature', 'type', 'Feature',
'geometry', ST_AsGeoJSON(st_makepoint(longitude,latitude))::jsonb, 'geometry', ST_AsGeoJSON(st_makepoint(longitude,latitude))::jsonb,

View File

@@ -174,7 +174,7 @@ begin
where channel = 'monitoring_online' and processed is null where channel = 'monitoring_online' and processed is null
order by stored asc order by stored asc
LOOP LOOP
RAISE NOTICE '-> cron_process_monitor_online_fn metadata_id [%]', process_rec.payload; RAISE NOTICE '-> cron_process_monitor_online_fn metadata_id [%]', process_rec.payload;
SELECT * INTO metadata_rec SELECT * INTO metadata_rec
FROM api.metadata FROM api.metadata
WHERE id = process_rec.payload::INTEGER; WHERE id = process_rec.payload::INTEGER;
@@ -238,7 +238,7 @@ $$ language plpgsql;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
public.cron_process_new_account_fn 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'; IS 'deprecated, init by pg_cron to check for new account pending update, if so perform process_account_queue_fn';
-- CRON for new account pending otp validation notification -- CRON for new account pending otp validation notification
CREATE FUNCTION cron_process_new_account_otp_validation_fn() RETURNS void AS $$ CREATE FUNCTION cron_process_new_account_otp_validation_fn() RETURNS void AS $$
@@ -267,7 +267,7 @@ $$ language plpgsql;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
public.cron_process_new_account_otp_validation_fn public.cron_process_new_account_otp_validation_fn
IS 'init by pg_cron to check for new account otp pending update, if so perform process_account_otp_validation_queue_fn'; IS 'deprecated, init by pg_cron to check for new account otp pending update, if so perform process_account_otp_validation_queue_fn';
-- CRON for new vessel pending notification -- CRON for new vessel pending notification
CREATE FUNCTION cron_process_new_vessel_fn() RETURNS void AS $$ CREATE FUNCTION cron_process_new_vessel_fn() RETURNS void AS $$
@@ -296,7 +296,7 @@ $$ language plpgsql;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
public.cron_process_new_vessel_fn 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'; IS 'deprecated, init by pg_cron to check for new vessel pending update, if so perform process_vessel_queue_fn';
-- CRON for new event notification -- CRON for new event notification
CREATE FUNCTION cron_process_new_notification_fn() RETURNS void AS $$ CREATE FUNCTION cron_process_new_notification_fn() RETURNS void AS $$

View File

@@ -36,7 +36,8 @@ INSERT INTO geocoders VALUES
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Tables for message template email/pushover/telegram -- Tables for message template email/pushover/telegram
-- --
CREATE TABLE IF NOT EXISTS email_templates( DROP TABLE IF EXISTS public.email_templates;
CREATE TABLE IF NOT EXISTS public.email_templates(
name TEXT UNIQUE, name TEXT UNIQUE,
email_subject TEXT, email_subject TEXT,
email_content TEXT, email_content TEXT,
@@ -94,7 +95,7 @@ INSERT INTO email_templates VALUES
E'Congratulations!\nPlease validate your account. Check your email!'), E'Congratulations!\nPlease validate your account. Check your email!'),
('email_valid', ('email_valid',
'Email verified', 'Email verified',
E'Hello __RECIPIENT__,\nCongratulations!\nYou successfully validate your account.\nThe PostgSail Team', E'Hello,\nCongratulations!\nYou successfully validate your account.\nThe PostgSail Team',
'Email verified', 'Email verified',
E'Hi!\nYou successfully validate your account.\n'), E'Hi!\nYou successfully validate your account.\n'),
('email_reset', ('email_reset',
@@ -104,9 +105,9 @@ INSERT INTO email_templates VALUES
E'You requested a password recovery. Check your email!\n'), E'You requested a password recovery. Check your email!\n'),
('telegram_otp', ('telegram_otp',
'Telegram bot', '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', E'Hello,\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',
'Telegram bot', 'Telegram bot',
E'Congratulations!\nTo connect your account to a @postgsail_bot. Check your email!\n'), E'Hello,\nTo connect your account to a @postgsail_bot. Check your email!\n'),
('telegram_valid', ('telegram_valid',
'Telegram bot', 'Telegram bot',
E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to your vessel, @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',
@@ -183,9 +184,9 @@ COMMENT ON COLUMN public.app_settings.value IS 'application settings value';
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Badges description -- Badges description
-- TODO add contiditions
-- --
CREATE TABLE IF NOT EXISTS badges( DROP TABLE IF EXISTS public.badges;
CREATE TABLE IF NOT EXISTS public.badges(
name TEXT UNIQUE, name TEXT UNIQUE,
description TEXT description TEXT
); );
@@ -205,25 +206,25 @@ INSERT INTO badges VALUES
'It takes a lot of skill to "thread that floating needle" but seems like you have mastered mooring with 10 nights on buoy!'), 'It takes a lot of skill to "thread that floating needle" but seems like you have mastered mooring with 10 nights on buoy!'),
('Anchormaster', ('Anchormaster',
'Hook, line and sinker, you have this anchoring thing down! 25 days on the hook for you!'), 'Hook, line and sinker, you have this anchoring thing down! 25 days on the hook for you!'),
('Traveler', ('Traveler todo',
'Who needs to fly when one can sail! You are an international sailor. À votre santé!'), 'Who needs to fly when one can sail! You are an international sailor. À votre santé!'),
('Stormtrooper', ('Stormtrooper',
'Just like the elite defenders of the Empire, here you are, our braving your own hydro-empire in windspeeds above 30kts. Nice work trooper! '), 'Just like the elite defenders of the Empire, here you are, our braving your own hydro-empire in windspeeds above 30kts. Nice work trooper! '),
('Club Alaska', ('Club Alaska',
'Home to the bears, glaciers, midnight sun and high adventure. Welcome to the Club Alaska Captain!'), 'Home to the bears, glaciers, midnight sun and high adventure. Welcome to the Club Alaska Captain!'),
('Tropical Traveler', ('Tropical Traveler',
'Look at you with your suntan, tropical drink and southern latitude!'), 'Look at you with your suntan, tropical drink and southern latitude!'),
('Aloha Award', ('Aloha Award',
'Ticking off over 2300 NM across the great blue Pacific makes you the rare recipient of the Aloha Award. Well done and Aloha sailor!'), 'Ticking off over 2300 NM across the great blue Pacific makes you the rare recipient of the Aloha Award. Well done and Aloha sailor!'),
('Tyee', ('Navigator Award',
'You made it to the Tyee Outstation, the friendliest dock in Pacific Northwest!'), 'Woohoo! You made it, Ticking off over 100NM in one go, well done sailor!'),
-- TODO the sea is big and the world is not limited to the US ('Captain Award',
('Mediterranean Traveler', 'Congratulation, you reach over 1000NM, well done sailor!');
'You made it trought the Mediterranean!');
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- aistypes description -- aistypes description
-- --
DROP TABLE IF EXISTS public.aistypes;
CREATE TABLE IF NOT EXISTS aistypes( CREATE TABLE IF NOT EXISTS aistypes(
id NUMERIC UNIQUE, id NUMERIC UNIQUE,
description TEXT description TEXT
@@ -319,9 +320,11 @@ INSERT INTO aistypes VALUES
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- MMSI MID Codes -- MMSI MID Codes
-- --
CREATE TABLE IF NOT EXISTS mid( DROP TABLE IF EXISTS public.mid;
CREATE TABLE IF NOT EXISTS public.mid(
country TEXT, country TEXT,
id NUMERIC UNIQUE id NUMERIC UNIQUE,
country_id INTEGER
); );
-- Description -- Description
COMMENT ON TABLE COMMENT ON TABLE
@@ -329,292 +332,557 @@ COMMENT ON TABLE
IS 'MMSI MID Codes (Maritime Mobile Service Identity) Filtered by Flag of Registration, https://www.marinevesseltraffic.com/2013/11/mmsi-mid-codes-by-flag.html'; IS 'MMSI MID Codes (Maritime Mobile Service Identity) Filtered by Flag of Registration, https://www.marinevesseltraffic.com/2013/11/mmsi-mid-codes-by-flag.html';
INSERT INTO mid VALUES INSERT INTO mid VALUES
('Adelie Land', 501), ('Adelie Land', 501, NULL),
('Afghanistan', 401), ('Afghanistan', 401, 4),
('Alaska', 303), ('Alaska', 303, 840),
('Albania', 201), ('Albania', 201, 8),
('Algeria', 605), ('Algeria', 605, 12),
('American Samoa', 559), ('American Samoa', 559, 16),
('Andorra', 202), ('Andorra', 202, 20),
('Angola', 603), ('Angola', 603, 24),
('Anguilla', 301), ('Anguilla', 301, 660),
('Antigua and Barbuda', 304), ('Antigua and Barbuda', 304, 28),
('Antigua and Barbuda', 305), ('Antigua and Barbuda', 305, 28),
('Argentina', 701), ('Argentina', 701, 32),
('Armenia', 216), ('Armenia', 216, 51),
('Aruba', 307), ('Aruba', 307, 533),
('Ascension Island', 608), ('Ascension Island', 608, NULL),
('Australia', 503), ('Australia', 503, 36),
('Austria', 203), ('Austria', 203, 40),
('Azerbaijan', 423), ('Azerbaijan', 423, 31),
('Azores', 204), ('Azores', 204, NULL),
('Bahamas', 308), ('Bahamas', 308, 44),
('Bahamas', 309), ('Bahamas', 309, 44),
('Bahamas', 311), ('Bahamas', 311, 44),
('Bahrain', 408), ('Bahrain', 408, 48),
('Bangladesh', 405), ('Bangladesh', 405, 50),
('Barbados', 314), ('Barbados', 314, 52),
('Belarus', 206), ('Belarus', 206, 112),
('Belgium', 205), ('Belgium', 205, 56),
('Belize', 312), ('Belize', 312, 84),
('Benin', 610), ('Benin', 610, 204),
('Bermuda', 310), ('Bermuda', 310, 60),
('Bhutan', 410), ('Bhutan', 410, 64),
('Bolivia', 720), ('Bolivia', 720, 68),
('Bosnia and Herzegovina', 478), ('Bosnia and Herzegovina', 478, 70),
('Botswana', 611), ('Botswana', 611, 72),
('Brazil', 710), ('Brazil', 710, 76),
('British Virgin Islands', 378), ('British Virgin Islands', 378, 92),
('Brunei Darussalam', 508), ('Brunei Darussalam', 508, 96),
('Bulgaria', 207), ('Bulgaria', 207, 100),
('Burkina Faso', 633), ('Burkina Faso', 633, 854),
('Burundi', 609), ('Burundi', 609, 108),
('Cambodia', 514), ('Cambodia', 514, 116),
('Cambodia', 515), ('Cambodia', 515, 116),
('Cameroon', 613), ('Cameroon', 613, 120),
('Canada', 316), ('Canada', 316, 124),
('Cape Verde', 617), ('Cape Verde', 617, 132),
('Cayman Islands', 319), ('Cayman Islands', 319, 136),
('Central African Republic', 612), ('Central African Republic', 612, 140),
('Chad', 670), ('Chad', 670, 148),
('Chile', 725), ('Chile', 725, 152),
('China', 412), ('China', 412, 156),
('China', 413), ('China', 413, 156),
('China', 414), ('China', 414, 156),
('Christmas Island', 516), ('Christmas Island', 516, 162),
('Cocos Islands', 523), ('Cocos Islands', 523, 166),
('Colombia', 730), ('Colombia', 730, 170),
('Comoros', 616), ('Comoros', 616, 174),
('Comoros', 620), ('Comoros', 620, 174),
('Congo', 615), ('Congo', 615, 178),
('Cook Islands', 518), ('Cook Islands', 518, 184),
('Costa Rica', 321), ('Costa Rica', 321, 188),
(E'Côte d\'Ivoire', 619), (E'Côte d\'Ivoire', 619, 384),
('Croatia', 238), ('Croatia', 238, 191),
('Crozet Archipelago', 618), ('Crozet Archipelago', 618, NULL),
('Cuba', 323), ('Cuba', 323, 192),
('Cyprus', 209), ('Cyprus', 209, 196),
('Cyprus', 210), ('Cyprus', 210, 196),
('Cyprus', 212), ('Cyprus', 212, 196),
('Czech Republic', 270), ('Czech Republic', 270, 203),
('Denmark', 219), ('Denmark', 219, 208),
('Denmark', 220), ('Denmark', 220, 208),
('Djibouti', 621), ('Djibouti', 621, 262),
('Dominica', 325), ('Dominica', 325, 212),
('Dominican Republic', 327), ('Dominican Republic', 327, 214),
('DR Congo', 676), ('DR Congo', 676, NULL),
('Ecuador', 735), ('Ecuador', 735, 218),
('Egypt', 622), ('Egypt', 622, 818),
('El Salvador', 359), ('El Salvador', 359, 222),
('Equatorial Guinea', 631), ('Equatorial Guinea', 631, 226),
('Eritrea', 625), ('Eritrea', 625, 232),
('Estonia', 276), ('Estonia', 276, 233),
('Ethiopia', 624), ('Ethiopia', 624, 231),
('Falkland Islands', 740), ('Falkland Islands', 740, 234),
('Faroe Islands', 231), ('Faroe Islands', 231, NULL),
('Fiji', 520), ('Fiji', 520, 242),
('Finland', 230), ('Finland', 230, 246),
('France', 226), ('France', 226, 250),
('France', 227), ('France', 227, 250),
('France', 228), ('France', 228, 250),
('French Polynesia', 546), ('French Polynesia', 546, 260),
('Gabonese Republic', 626), ('Gabonese Republic', 626, 266),
('Gambia', 629), ('Gambia', 629, 270),
('Georgia', 213), ('Georgia', 213, 268),
('Germany', 211), ('Germany', 211, 276),
('Germany', 218), ('Germany', 218, 276),
('Ghana', 627), ('Ghana', 627, 288),
('Gibraltar', 236), ('Gibraltar', 236, 292),
('Greece', 237), ('Greece', 237, 300),
('Greece', 239), ('Greece', 239, 300),
('Greece', 240), ('Greece', 240, 300),
('Greece', 241), ('Greece', 241, 300),
('Greenland', 331), ('Greenland', 331, 304),
('Grenada', 330), ('Grenada', 330, 308),
('Guadeloupe', 329), ('Guadeloupe', 329, 312),
('Guatemala', 332), ('Guatemala', 332, 320),
('Guiana', 745), ('Guiana', 745, 324),
('Guinea', 632), ('Guinea', 632, 324),
('Guinea-Bissau', 630), ('Guinea-Bissau', 630, 624),
('Guyana', 750), ('Guyana', 750, 328),
('Haiti', 336), ('Haiti', 336, 332),
('Honduras', 334), ('Honduras', 334, 340),
('Hong Kong', 477), ('Hong Kong', 477, 344),
('Hungary', 243), ('Hungary', 243, 348),
('Iceland', 251), ('Iceland', 251, 352),
('India', 419), ('India', 419, 356),
('Indonesia', 525), ('Indonesia', 525, 360),
('Iran', 422), ('Iran', 422, 364),
('Iraq', 425), ('Iraq', 425, 368),
('Ireland', 250), ('Ireland', 250, 372),
('Israel', 428), ('Israel', 428, 376),
('Italy', 247), ('Italy', 247, 380),
('Jamaica', 339), ('Jamaica', 339, 388),
('Japan', 431), ('Japan', 431, 392),
('Japan', 432), ('Japan', 432, 392),
('Jordan', 438), ('Jordan', 438, 400),
('Kazakhstan', 436), ('Kazakhstan', 436, 398),
('Kenya', 634), ('Kenya', 634, 404),
('Kerguelen Islands', 635), ('Kerguelen Islands', 635, NULL),
('Kiribati', 529), ('Kiribati', 529, 296),
('Kuwait', 447), ('Kuwait', 447, 414),
('Kyrgyzstan', 451), ('Kyrgyzstan', 451, 417),
('Lao', 531), ('Lao', 531, 418),
('Latvia', 275), ('Latvia', 275, 428),
('Lebanon', 450), ('Lebanon', 450, 422),
('Lesotho', 644), ('Lesotho', 644, 426),
('Liberia', 636), ('Liberia', 636, 430),
('Liberia', 637), ('Liberia', 637, 430),
('Libya', 642), ('Libya', 642, 434),
('Liechtenstein', 252), ('Liechtenstein', 252, 438),
('Lithuania', 277), ('Lithuania', 277, 440),
('Luxembourg', 253), ('Luxembourg', 253, 442),
('Macao', 453), ('Macao', 453, 446),
('Madagascar', 647), ('Madagascar', 647, 450),
('Madeira', 255), ('Madeira', 255, NULL),
('Makedonia', 274), ('Makedonia', 274, NULL),
('Malawi', 655), ('Malawi', 655, 454),
('Malaysia', 533), ('Malaysia', 533, 458),
('Maldives', 455), ('Maldives', 455, 462),
('Mali', 649), ('Mali', 649, 466),
('Malta', 215), ('Malta', 215, 470),
('Malta', 229), ('Malta', 229, 470),
('Malta', 248), ('Malta', 248, 470),
('Malta', 249), ('Malta', 249, 470),
('Malta', 256), ('Malta', 256, 470),
('Marshall Islands', 538), ('Marshall Islands', 538, 584),
('Martinique', 347), ('Martinique', 347, 474),
('Mauritania', 654), ('Mauritania', 654, 478),
('Mauritius', 645), ('Mauritius', 645, 480),
('Mexico', 345), ('Mexico', 345, 484),
('Micronesia', 510), ('Micronesia', 510, 583),
('Moldova', 214), ('Moldova', 214, 498),
('Monaco', 254), ('Monaco', 254, 492),
('Mongolia', 457), ('Mongolia', 457, 496),
('Montenegro', 262), ('Montenegro', 262, 499),
('Montserrat', 348), ('Montserrat', 348, 500),
('Morocco', 242), ('Morocco', 242, 504),
('Mozambique', 650), ('Mozambique', 650, 508),
('Myanmar', 506), ('Myanmar', 506, 104),
('Namibia', 659), ('Namibia', 659, 516),
('Nauru', 544), ('Nauru', 544, 520),
('Nepal', 459), ('Nepal', 459, 524),
('Netherlands', 244), ('Netherlands', 244, 528),
('Netherlands', 245), ('Netherlands', 245, 528),
('Netherlands', 246), ('Netherlands', 246, 528),
('Netherlands Antilles', 306), ('Netherlands Antilles', 306, NULL),
('New Caledonia', 540), ('New Caledonia', 540, 540),
('New Zealand', 512), ('New Zealand', 512, 554),
('Nicaragua', 350), ('Nicaragua', 350, 558),
('Niger', 656), ('Niger', 656, 562),
('Nigeria', 657), ('Nigeria', 657, 566),
('Niue', 542), ('Niue', 542, 570),
('North Korea', 445), ('North Korea', 445, 408),
('Northern Mariana Islands', 536), ('Northern Mariana Islands', 536, 580),
('Norway', 257), ('Norway', 257, 578),
('Norway', 258), ('Norway', 258, 578),
('Norway', 259), ('Norway', 259, 578),
('Oman', 461), ('Oman', 461, 512),
('Pakistan', 463), ('Pakistan', 463, 586),
('Palau', 511), ('Palau', 511, 585),
('Palestine', 443), ('Palestine', 443, 275),
('Panama', 351), ('Panama', 351, 591),
('Panama', 352), ('Panama', 352, 591),
('Panama', 353), ('Panama', 353, 591),
('Panama', 354), ('Panama', 354, 591),
('Panama', 355), ('Panama', 355, 591),
('Panama', 356), ('Panama', 356, 591),
('Panama', 357), ('Panama', 357, 591),
('Panama', 370), ('Panama', 370, 591),
('Panama', 371), ('Panama', 371, 591),
('Panama', 372), ('Panama', 372, 591),
('Panama', 373), ('Panama', 373, 591),
('Papua New Guinea', 553), ('Papua New Guinea', 553, 598),
('Paraguay', 755), ('Paraguay', 755, 600),
('Peru', 760), ('Peru', 760, 604),
('Philippines', 548), ('Philippines', 548, 608),
('Pitcairn Island', 555), ('Pitcairn Island', 555, 612),
('Poland', 261), ('Poland', 261, 616),
('Portugal', 263), ('Portugal', 263, 620),
('Puerto Rico', 358), ('Puerto Rico', 358, 630),
('Qatar', 466), ('Qatar', 466, 634),
('Reunion', 660), ('Reunion', 660, 638),
('Romania', 264), ('Romania', 264, 642),
('Russian Federation', 273), ('Russian Federation', 273, 643),
('Rwanda', 661), ('Rwanda', 661, 646),
('Saint Helena', 665), ('Saint Helena', 665, 654),
('Saint Kitts and Nevis', 341), ('Saint Kitts and Nevis', 341, 659),
('Saint Lucia', 343), ('Saint Lucia', 343, 662),
('Saint Paul and Amsterdam Islands', 607), ('Saint Paul and Amsterdam Islands', 607, NULL),
('Saint Pierre and Miquelon', 361), ('Saint Pierre and Miquelon', 361, 666),
('Samoa', 561), ('Samoa', 561, 882),
('San Marino', 268), ('San Marino', 268, 674),
('Sao Tome and Principe', 668), ('Sao Tome and Principe', 668, 678),
('Saudi Arabia', 403), ('Saudi Arabia', 403, 682),
('Senegal', 663), ('Senegal', 663, 686),
('Serbia', 279), ('Serbia', 279, 688),
('Seychelles', 664), ('Seychelles', 664, 690),
('Sierra Leone', 667), ('Sierra Leone', 667, 694),
('Singapore', 563), ('Singapore', 563, 702),
('Singapore', 564), ('Singapore', 564, 702),
('Singapore', 565), ('Singapore', 565, 702),
('Singapore', 566), ('Singapore', 566, 702),
('Slovakia', 267), ('Slovakia', 267, 703),
('Slovenia', 278), ('Slovenia', 278, 705),
('Solomon Islands', 557), ('Solomon Islands', 557, 90),
('Somalia', 666), ('Somalia', 666, 706),
('South Africa', 601), ('South Africa', 601, 710),
('South Korea', 440), ('South Korea', 440, 410),
('South Korea', 441), ('South Korea', 441, 410),
('South Sudan', 638), ('South Sudan', 638, 728),
('Spain', 224), ('Spain', 224, 724),
('Spain', 225), ('Spain', 225, 724),
('Sri Lanka', 417), ('Sri Lanka', 417, 144),
('St Vincent and the Grenadines', 375), ('St Vincent and the Grenadines', 375, 670),
('St Vincent and the Grenadines', 376), ('St Vincent and the Grenadines', 376, 670),
('St Vincent and the Grenadines', 377), ('St Vincent and the Grenadines', 377, 670),
('Sudan', 662), ('Sudan', 662, 729),
('Suriname', 765), ('Suriname', 765, 740),
('Swaziland', 669), ('Swaziland', 669, 748),
('Sweden', 265), ('Sweden', 265, 752),
('Sweden', 266), ('Sweden', 266, 752),
('Switzerland', 269), ('Switzerland', 269, 756),
('Syria', 468), ('Syria', 468, 760),
('Taiwan', 416), ('Taiwan', 416, 158),
('Tajikistan', 472), ('Tajikistan', 472, 762),
('Tanzania', 674), ('Tanzania', 674, 834),
('Tanzania', 677), ('Tanzania', 677, 834),
('Thailand', 567), ('Thailand', 567, 764),
('Togolese', 671), ('Togolese', 671, 768),
('Tonga', 570), ('Tonga', 570, 776),
('Trinidad and Tobago', 362), ('Trinidad and Tobago', 362, 780),
('Tunisia', 672), ('Tunisia', 672, 788),
('Turkey', 271), ('Turkey', 271, 792),
('Turkmenistan', 434), ('Turkmenistan', 434, 795),
('Turks and Caicos Islands', 364), ('Turks and Caicos Islands', 364, 796),
('Tuvalu', 572), ('Tuvalu', 572, 798),
('Uganda', 675), ('Uganda', 675, 800),
('Ukraine', 272), ('Ukraine', 272, 804),
('United Arab Emirates', 470), ('United Arab Emirates', 470, 784),
('United Kingdom', 232), ('United Kingdom', 232, 826),
('United Kingdom', 233), ('United Kingdom', 233, 826),
('United Kingdom', 234), ('United Kingdom', 234, 826),
('United Kingdom', 235), ('United Kingdom', 235, 826),
('Uruguay', 770), ('Uruguay', 770, 858),
('US Virgin Islands', 379), ('US Virgin Islands', 379, 850),
('USA', 338), ('USA', 338, 840),
('USA', 366), ('USA', 366, 840),
('USA', 367), ('USA', 367, 840),
('USA', 368), ('USA', 368, 840),
('USA', 369), ('USA', 369, 840),
('Uzbekistan', 437), ('Uzbekistan', 437, 860),
('Vanuatu', 576), ('Vanuatu', 576, 548),
('Vanuatu', 577), ('Vanuatu', 577, 548),
('Vatican City', 208), ('Vatican City', 208, NULL),
('Venezuela', 775), ('Venezuela', 775, 862),
('Vietnam', 574), ('Vietnam', 574, 704),
('Wallis and Futuna Islands', 578), ('Wallis and Futuna Islands', 578, 876),
('Yemen', 473), ('Yemen', 473, 887),
('Yemen', 475), ('Yemen', 475, 887),
('Zambia', 678), ('Zambia', 678, 894),
('Zimbabwe', 679); ('Zimbabwe', 679, 716);
---------------------------------------------------------------------------
--
DROP TABLE IF EXISTS public.iso3166;
CREATE TABLE IF NOT EXISTS public.iso3166(
id INTEGER,
country TEXT,
alpha_2 TEXT,
alpha_3 TEXT
);
-- Description
COMMENT ON TABLE
public.iso3166
IS 'This is a complete list of all country ISO codes as described in the ISO 3166 international standard. Country Codes Alpha-2 & Alpha-3 https://www.iban.com/country-codes';
INSERT INTO iso3166 VALUES
(4,'Afghanistan','AF','AFG'),
(8,'Albania','AL','ALB'),
(12,'Algeria','DZ','DZA'),
(16,'American Samoa','AS','ASM'),
(20,'Andorra','AD','AND'),
(24,'Angola','AO','AGO'),
(660,'Anguilla','AI','AIA'),
(10,'Antarctica','AQ','ATA'),
(28,'Antigua and Barbuda','AG','ATG'),
(32,'Argentina','AR','ARG'),
(51,'Armenia','AM','ARM'),
(533,'Aruba','AW','ABW'),
(36,'Australia','AU','AUS'),
(40,'Austria','AT','AUT'),
(31,'Azerbaijan','AZ','AZE'),
(44,'Bahamas (the)','BS','BHS'),
(48,'Bahrain','BH','BHR'),
(50,'Bangladesh','BD','BGD'),
(52,'Barbados','BB','BRB'),
(112,'Belarus','BY','BLR'),
(56,'Belgium','BE','BEL'),
(84,'Belize','BZ','BLZ'),
(204,'Benin','BJ','BEN'),
(60,'Bermuda','BM','BMU'),
(64,'Bhutan','BT','BTN'),
(68,E'Bolivia (Plurinational State of)','BO','BOL'),
(535,'Bonaire, Sint Eustatius and Saba','BQ','BES'),
(70,'Bosnia and Herzegovina','BA','BIH'),
(72,'Botswana','BW','BWA'),
(74,'Bouvet Island','BV','BVT'),
(76,'Brazil','BR','BRA'),
(86,E'British Indian Ocean Territory (the)','IO','IOT'),
(96,'Brunei Darussalam','BN','BRN'),
(100,'Bulgaria','BG','BGR'),
(854,'Burkina Faso','BF','BFA'),
(108,'Burundi','BI','BDI'),
(132,'Cabo Verde','CV','CPV'),
(116,'Cambodia','KH','KHM'),
(120,'Cameroon','CM','CMR'),
(124,'Canada','CA','CAN'),
(136,E'Cayman Islands (the)','KY','CYM'),
(140,E'Central African Republic (the)','CF','CAF'),
(148,'Chad','TD','TCD'),
(152,'Chile','CL','CHL'),
(156,'China','CN','CHN'),
(162,'Christmas Island','CX','CXR'),
(166,E'Cocos (Keeling) Islands (the)','CC','CCK'),
(170,'Colombia','CO','COL'),
(174,'Comoros (the)','KM','COM'),
(180,E'Congo (the Democratic Republic of the)','CD','COD'),
(178,E'Congo (the)','CG','COG'),
(184,E'Cook Islands (the)','CK','COK'),
(188,'Costa Rica','CR','CRI'),
(191,'Croatia','HR','HRV'),
(192,'Cuba','CU','CUB'),
(531,'Curaçao','CW','CUW'),
(196,'Cyprus','CY','CYP'),
(203,'Czechia','CZ','CZE'),
(384,E'Côte d\'Ivoire','CI','CIV'),
(208,'Denmark','DK','DNK'),
(262,'Djibouti','DJ','DJI'),
(212,'Dominica','DM','DMA'),
(214,E'Dominican Republic (the)','DO','DOM'),
(218,'Ecuador','EC','ECU'),
(818,'Egypt','EG','EGY'),
(222,'El Salvador','SV','SLV'),
(226,'Equatorial Guinea','GQ','GNQ'),
(232,'Eritrea','ER','ERI'),
(233,'Estonia','EE','EST'),
(748,'Eswatini','SZ','SWZ'),
(231,'Ethiopia','ET','ETH'),
(238,E'Falkland Islands (the) [Malvinas]','FK','FLK'),
(234,E'Faroe Islands (the)','FO','FRO'),
(242,'Fiji','FJ','FJI'),
(246,'Finland','FI','FIN'),
(250,'France','FR','FRA'),
(254,'French Guiana','GF','GUF'),
(258,'French Polynesia','PF','PYF'),
(260,E'French Southern Territories (the)','TF','ATF'),
(266,'Gabon','GA','GAB'),
(270,E'Gambia (the)','GM','GMB'),
(268,'Georgia','GE','GEO'),
(276,'Germany','DE','DEU'),
(288,'Ghana','GH','GHA'),
(292,'Gibraltar','GI','GIB'),
(300,'Greece','GR','GRC'),
(304,'Greenland','GL','GRL'),
(308,'Grenada','GD','GRD'),
(312,'Guadeloupe','GP','GLP'),
(316,'Guam','GU','GUM'),
(320,'Guatemala','GT','GTM'),
(831,'Guernsey','GG','GGY'),
(324,'Guinea','GN','GIN'),
(624,'Guinea-Bissau','GW','GNB'),
(328,'Guyana','GY','GUY'),
(332,'Haiti','HT','HTI'),
(334,'Heard Island and McDonald Islands','HM','HMD'),
(336,E'Holy See (the)','VA','VAT'),
(340,'Honduras','HN','HND'),
(344,'Hong Kong','HK','HKG'),
(348,'Hungary','HU','HUN'),
(352,'Iceland','IS','ISL'),
(356,'India','IN','IND'),
(360,'Indonesia','ID','IDN'),
(364,E'Iran (Islamic Republic of)','IR','IRN'),
(368,'Iraq','IQ','IRQ'),
(372,'Ireland','IE','IRL'),
(833,'Isle of Man','IM','IMN'),
(376,'Israel','IL','ISR'),
(380,'Italy','IT','ITA'),
(388,'Jamaica','JM','JAM'),
(392,'Japan','JP','JPN'),
(832,'Jersey','JE','JEY'),
(400,'Jordan','JO','JOR'),
(398,'Kazakhstan','KZ','KAZ'),
(404,'Kenya','KE','KEN'),
(296,'Kiribati','KI','KIR'),
(408,E'Korea (the Democratic People\'s Republic of)','KP','PRK'),
(410,E'Korea (the Republic of)','KR','KOR'),
(414,'Kuwait','KW','KWT'),
(417,'Kyrgyzstan','KG','KGZ'),
(418,E'Lao People\'s Democratic Republic (the)','LA','LAO'),
(428,'Latvia','LV','LVA'),
(422,'Lebanon','LB','LBN'),
(426,'Lesotho','LS','LSO'),
(430,'Liberia','LR','LBR'),
(434,'Libya','LY','LBY'),
(438,'Liechtenstein','LI','LIE'),
(440,'Lithuania','LT','LTU'),
(442,'Luxembourg','LU','LUX'),
(446,'Macao','MO','MAC'),
(450,'Madagascar','MG','MDG'),
(454,'Malawi','MW','MWI'),
(458,'Malaysia','MY','MYS'),
(462,'Maldives','MV','MDV'),
(466,'Mali','ML','MLI'),
(470,'Malta','MT','MLT'),
(584,E'Marshall Islands (the)','MH','MHL'),
(474,'Martinique','MQ','MTQ'),
(478,'Mauritania','MR','MRT'),
(480,'Mauritius','MU','MUS'),
(175,'Mayotte','YT','MYT'),
(484,'Mexico','MX','MEX'),
(583,E'Micronesia (Federated States of)','FM','FSM'),
(498,E'Moldova (the Republic of)','MD','MDA'),
(492,'Monaco','MC','MCO'),
(496,'Mongolia','MN','MNG'),
(499,'Montenegro','ME','MNE'),
(500,'Montserrat','MS','MSR'),
(504,'Morocco','MA','MAR'),
(508,'Mozambique','MZ','MOZ'),
(104,'Myanmar','MM','MMR'),
(516,'Namibia','NA','NAM'),
(520,'Nauru','NR','NRU'),
(524,'Nepal','NP','NPL'),
(528,E'Netherlands (the)','NL','NLD'),
(540,'New Caledonia','NC','NCL'),
(554,'New Zealand','NZ','NZL'),
(558,'Nicaragua','NI','NIC'),
(562,E'Niger (the)','NE','NER'),
(566,'Nigeria','NG','NGA'),
(570,'Niue','NU','NIU'),
(574,'Norfolk Island','NF','NFK'),
(580,E'Northern Mariana Islands (the)','MP','MNP'),
(578,'Norway','NO','NOR'),
(512,'Oman','OM','OMN'),
(586,'Pakistan','PK','PAK'),
(585,'Palau','PW','PLW'),
(275,'Palestine, State of','PS','PSE'),
(591,'Panama','PA','PAN'),
(598,'Papua New Guinea','PG','PNG'),
(600,'Paraguay','PY','PRY'),
(604,'Peru','PE','PER'),
(608,E'Philippines (the)','PH','PHL'),
(612,'Pitcairn','PN','PCN'),
(616,'Poland','PL','POL'),
(620,'Portugal','PT','PRT'),
(630,'Puerto Rico','PR','PRI'),
(634,'Qatar','QA','QAT'),
(807,'Republic of North Macedonia','MK','MKD'),
(642,'Romania','RO','ROU'),
(643,'Russian Federation (the)','RU','RUS'),
(646,'Rwanda','RW','RWA'),
(638,'Réunion','RE','REU'),
(652,'Saint Barthélemy','BL','BLM'),
(654,'Saint Helena, Ascension and Tristan da Cunha','SH','SHN'),
(659,'Saint Kitts and Nevis','KN','KNA'),
(662,'Saint Lucia','LC','LCA'),
(663,'Saint Martin (French part)','MF','MAF'),
(666,'Saint Pierre and Miquelon','PM','SPM'),
(670,'Saint Vincent and the Grenadines','VC','VCT'),
(882,'Samoa','WS','WSM'),
(674,'San Marino','SM','SMR'),
(678,'Sao Tome and Principe','ST','STP'),
(682,'Saudi Arabia','SA','SAU'),
(686,'Senegal','SN','SEN'),
(688,'Serbia','RS','SRB'),
(690,'Seychelles','SC','SYC'),
(694,'Sierra Leone','SL','SLE'),
(702,'Singapore','SG','SGP'),
(534,'Sint Maarten (Dutch part)','SX','SXM'),
(703,'Slovakia','SK','SVK'),
(705,'Slovenia','SI','SVN'),
(90,'Solomon Islands','SB','SLB'),
(706,'Somalia','SO','SOM'),
(710,'South Africa','ZA','ZAF'),
(239,'South Georgia and the South Sandwich Islands','GS','SGS'),
(728,'South Sudan','SS','SSD'),
(724,'Spain','ES','ESP'),
(144,'Sri Lanka','LK','LKA'),
(729,'Sudan (the)','SD','SDN'),
(740,'Suriname','SR','SUR'),
(744,'Svalbard and Jan Mayen','SJ','SJM'),
(752,'Sweden','SE','SWE'),
(756,'Switzerland','CH','CHE'),
(760,'Syrian Arab Republic','SY','SYR'),
(158,'Taiwan (Province of China)','TW','TWN'),
(762,'Tajikistan','TJ','TJK'),
(834,'Tanzania, United Republic of','TZ','TZA'),
(764,'Thailand','TH','THA'),
(626,'Timor-Leste','TL','TLS'),
(768,'Togo','TG','TGO'),
(772,'Tokelau','TK','TKL'),
(776,'Tonga','TO','TON'),
(780,'Trinidad and Tobago','TT','TTO'),
(788,'Tunisia','TN','TUN'),
(792,'Turkey','TR','TUR'),
(795,'Turkmenistan','TM','TKM'),
(796,'Turks and Caicos Islands (the)','TC','TCA'),
(798,'Tuvalu','TV','TUV'),
(800,'Uganda','UG','UGA'),
(804,'Ukraine','UA','UKR'),
(784,'United Arab Emirates (the)','AE','ARE'),
(826,'United Kingdom of Great Britain and Northern Ireland (the)','GB','GBR'),
(581,'United States Minor Outlying Islands (the)','UM','UMI'),
(840,'United States of America (the)','US','USA'),
(858,'Uruguay','UY','URY'),
(860,'Uzbekistan','UZ','UZB'),
(548,'Vanuatu','VU','VUT'),
(862,'Venezuela (Bolivarian Republic of)','VE','VEN'),
(704,'Viet Nam','VN','VNM'),
(92,'Virgin Islands (British)','VG','VGB'),
(850,'Virgin Islands (U.S.)','VI','VIR'),
(876,'Wallis and Futuna','WF','WLF'),
(732,'Western Sahara','EH','ESH'),
(887,'Yemen','YE','YEM'),
(894,'Zambia','ZM','ZMB'),
(716,'Zimbabwe','ZW','ZWE'),
(248,E'Åland Islands','AX','ALA');

View File

@@ -12,7 +12,7 @@ CREATE SCHEMA IF NOT EXISTS public;
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- Functions public schema -- Functions public schema
-- process single cron event, process_[logbook|stay|moorage|badge]_queue_fn() -- process single cron event, process_[logbook|stay|moorage]_queue_fn()
-- --
CREATE OR REPLACE FUNCTION logbook_metrics_dwithin_fn( CREATE OR REPLACE FUNCTION logbook_metrics_dwithin_fn(
@@ -213,7 +213,7 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
END IF; END IF;
PERFORM set_config('vessel.client_id', logbook_rec.client_id, false); PERFORM set_config('vessel.client_id', logbook_rec.client_id, false);
--RAISE WARNING 'public.process_logbook_queue_fn() scheduler vessel.client_id %', current_setting('vessel.client_id', false); --RAISE WARNING 'public.process_logbook_queue_fn() scheduler vessel.client_id %, user.id', current_setting('vessel.client_id', false), current_setting('user.id', false);
-- Check if all metrics are within 10meters base on geo loc -- Check if all metrics are within 10meters base on geo loc
count_metric := logbook_metrics_dwithin_fn(logbook_rec._from_time::TEXT, logbook_rec._to_time::TEXT, logbook_rec._from_lng::NUMERIC, logbook_rec._from_lat::NUMERIC); count_metric := logbook_metrics_dwithin_fn(logbook_rec._from_time::TEXT, logbook_rec._to_time::TEXT, logbook_rec._from_lng::NUMERIC, logbook_rec._from_lat::NUMERIC);
@@ -313,6 +313,11 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
RAISE DEBUG '-> debug process_logbook_queue_fn log_settings [%]', log_settings; RAISE DEBUG '-> debug process_logbook_queue_fn log_settings [%]', log_settings;
-- Send notification -- Send notification
PERFORM send_notification_fn('logbook'::TEXT, user_settings::JSONB); PERFORM send_notification_fn('logbook'::TEXT, user_settings::JSONB);
-- Process badges
RAISE NOTICE '--> user_settings [%]', user_settings->>'email'::TEXT;
PERFORM set_config('user.email', user_settings->>'email'::TEXT, false);
PERFORM badges_logbook_fn(logbook_rec.id);
PERFORM badges_geom_fn(logbook_rec.id);
END; END;
$process_logbook_queue$ LANGUAGE plpgsql; $process_logbook_queue$ LANGUAGE plpgsql;
-- Description -- Description
@@ -372,6 +377,7 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
DECLARE DECLARE
stay_rec record; stay_rec record;
moorage_rec record; moorage_rec record;
user_settings jsonb;
BEGIN BEGIN
RAISE NOTICE 'process_moorage_queue_fn'; RAISE NOTICE 'process_moorage_queue_fn';
-- If _id is not NULL -- If _id is not NULL
@@ -394,6 +400,8 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
RETURN; RETURN;
END IF; END IF;
PERFORM set_config('vessel.client_id', stay_rec.client_id, false);
-- Do we have an existing stay within 100m of the new moorage -- Do we have an existing stay within 100m of the new moorage
FOR moorage_rec in FOR moorage_rec in
SELECT SELECT
@@ -451,6 +459,9 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
Geography(ST_MakePoint(stay_rec.longitude, stay_rec.latitude)) Geography(ST_MakePoint(stay_rec.longitude, stay_rec.latitude))
); );
END IF; END IF;
-- Process badges
PERFORM badges_moorages_fn();
END; END;
$process_moorage_queue$ LANGUAGE plpgsql; $process_moorage_queue$ LANGUAGE plpgsql;
-- Description -- Description
@@ -560,7 +571,7 @@ AS $process_notification_queue$
RETURN; RETURN;
END IF; END IF;
RAISE NOTICE '--> process_notification_queue_fn type [%] [%]', _email,message_type; RAISE NOTICE '--> process_notification_queue_fn type [%] [%]', _email, message_type;
-- set user email variable -- set user email variable
PERFORM set_config('user.email', account_rec.email, false); PERFORM set_config('user.email', account_rec.email, false);
-- Generate user_settings user settings -- Generate user_settings user settings
@@ -701,12 +712,12 @@ AS $send_notification$
END IF; END IF;
-- Send notification telegram -- Send notification telegram
SELECT (preferences->'telegram'->'from'->'id') IS NOT NULL,preferences['telegram']['from']['id'] INTO _telegram_notifications,_telegram_chat_id SELECT (preferences->'telegram'->'chat'->'id') IS NOT NULL,preferences['telegram']['chat']['id'] INTO _telegram_notifications,_telegram_chat_id
FROM auth.accounts a FROM auth.accounts a
WHERE a.email = user_settings->>'email'::TEXT; WHERE a.email = user_settings->>'email'::TEXT;
RAISE NOTICE '--> send_notification_fn telegram_notifications [%]', _telegram_notifications; RAISE NOTICE '--> send_notification_fn telegram_notifications [%]', _telegram_notifications;
-- If telegram app settings set and if telegram user settings set -- If telegram app settings set and if telegram user settings set
IF app_settings['app.telegram_bot_token'] IS NOT NULL AND _telegram_notifications IS True THEN IF app_settings['app.telegram_bot_token'] IS NOT NULL AND _telegram_notifications IS True AND _phone_notifications IS True THEN
SELECT json_build_object('telegram_chat_id', _telegram_chat_id) into telegram_settings; SELECT json_build_object('telegram_chat_id', _telegram_chat_id) into telegram_settings;
SELECT user_settings::JSONB || telegram_settings::JSONB into user_settings; SELECT user_settings::JSONB || telegram_settings::JSONB into user_settings;
--RAISE NOTICE '--> send_notification_fn user_settings + telegram [%]', user_settings; --RAISE NOTICE '--> send_notification_fn user_settings + telegram [%]', user_settings;
@@ -737,13 +748,15 @@ AS $get_user_settings_from_clientid$
'recipient', a.first, 'recipient', a.first,
'email', v.owner_email, 'email', v.owner_email,
'settings', a.preferences, 'settings', a.preferences,
'pushover_key', a.preferences->'pushover_key', 'pushover_key', a.preferences->'pushover_key'
'badges', a.preferences->'badges' --'badges', a.preferences->'badges'
) INTO user_settings ) INTO user_settings
FROM auth.accounts a, auth.vessels v, api.metadata m FROM auth.accounts a, auth.vessels v, api.metadata m
WHERE m.mmsi = v.mmsi WHERE m.vessel_id = v.vessel_id
AND m.client_id = clientid AND m.client_id = clientid
AND lower(a.email) = lower(v.owner_email); AND lower(a.email) = lower(v.owner_email);
PERFORM set_config('user.email', user_settings->>'email'::TEXT, false);
PERFORM set_config('user.recipient', user_settings->>'recipient'::TEXT, false);
END; END;
$get_user_settings_from_clientid$ LANGUAGE plpgsql; $get_user_settings_from_clientid$ LANGUAGE plpgsql;
-- Description -- Description
@@ -751,77 +764,309 @@ COMMENT ON FUNCTION
public.get_user_settings_from_clientid_fn public.get_user_settings_from_clientid_fn
IS 'get user settings details from a clientid, initiate for notifications'; IS 'get user settings details from a clientid, initiate for notifications';
DROP FUNCTION IF EXISTS set_vessel_settings_from_clientid_fn; DROP FUNCTION IF EXISTS set_vessel_settings_from_vesselid_fn;
CREATE OR REPLACE FUNCTION set_vessel_settings_from_clientid_fn( CREATE OR REPLACE FUNCTION set_vessel_settings_from_vesselid_fn(
IN clientid TEXT, IN vesselid TEXT,
OUT vessel_settings JSONB OUT vessel_settings JSONB
) RETURNS JSONB ) RETURNS JSONB
AS $set_vessel_settings_from_clientid$ AS $set_vessel_settings_from_vesselid$
DECLARE DECLARE
BEGIN BEGIN
-- If client_id is not NULL -- If client_id is not NULL
IF clientid IS NULL OR clientid = '' THEN IF vesselid IS NULL OR vesselid = '' THEN
RAISE WARNING '-> set_vessel_settings_from_clientid_fn invalid input %', clientid; RAISE WARNING '-> set_vessel_settings_from_vesselid_fn invalid input %', vesselid;
END IF; END IF;
SELECT SELECT
json_build_object( json_build_object(
'name' , v.name, 'name' , v.name,
'mmsi', v.mmsi, 'vessel_id', v.vesselid,
'client_id', m.client_id 'client_id', m.client_id
) INTO vessel_settings ) INTO vessel_settings
FROM auth.accounts a, auth.vessels v, api.metadata m FROM auth.accounts a, auth.vessels v, api.metadata m
WHERE m.mmsi = v.mmsi WHERE m.vessel_id = v.vessel_id
AND m.client_id = clientid; AND m.client_id = clientid;
PERFORM set_config('vessel.mmsi', vessel_rec.mmsi, false); PERFORM set_config('vessel.name', vessel_settings->>'name'::TEXT, false);
PERFORM set_config('vessel.name', vessel_rec.name, false); PERFORM set_config('vessel.client_id', vessel_settings->>'client_id'::TEXT, false);
PERFORM set_config('vessel.client_id', vessel_rec.client_id, false); PERFORM set_config('vessel.vessel_id', vessel_settings->>'vessel_id'::TEXT, false);
END; END;
$set_vessel_settings_from_clientid$ LANGUAGE plpgsql; $set_vessel_settings_from_vesselid$ LANGUAGE plpgsql;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
public.set_vessel_settings_from_clientid_fn public.set_vessel_settings_from_vesselid_fn
IS 'set_vessel settings details from a clientid, initiate for process queue functions'; IS 'set_vessel settings details from a vesselid, initiate for process queue functions';
create function public.process_badge_queue_fn() RETURNS void AS $process_badge_queue$ ---------------------------------------------------------------------------
declare -- Badges
badge_rec record; --
badges_arr record; CREATE OR REPLACE FUNCTION public.badges_logbook_fn(IN logbook_id integer) RETURNS VOID AS $badges_logbook$
begin DECLARE
SELECT json_array_elements_text((a.preferences->'badges')::json) from auth.accounts a; _badges jsonb;
FOR badge_rec in _exist BOOLEAN := null;
SELECT total integer;
name max_wind_speed integer;
FROM badges distance integer;
LOOP badge text;
-- found previous stay within 100m of the new moorage user_settings jsonb;
IF moorage_rec.id IS NOT NULL AND moorage_rec.id > 0 THEN BEGIN
RAISE NOTICE 'Found previous stay within 100m of moorage %', moorage_rec;
EXIT; -- exit loop -- Helmsman = first log entry
END IF; SELECT (preferences->'badges'->'Helmsman') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
END LOOP; if _exist is false THEN
-- Helmsman -- is first logbook?
-- select count(l.id) api.logbook l where count(l.id) = 1; select count(*) into total from api.logbook l where client_id = current_setting('vessel.client_id', false);
-- Wake Maker if total >= 1 then
-- select max(l.max_wind_speed) api.logbook l where l.max_wind_speed >= 15; -- Add badge
-- Explorer badge := '{"Helmsman": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
-- select sum(m.stay_duration) api.stays s where home_flag is false; -- Get existing badges
-- Mooring Pro SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- select sum(m.stay_duration) api.stays s where stay_code = 3; -- Merge badges
-- Anchormaster SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- select sum(m.stay_duration) api.stays s where stay_code = 2; -- Update badges
-- Traveler PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- todo country to country. -- Gather user settings
-- Stormtrooper user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
-- select max(l.max_wind_speed) api.logbook l where l.max_wind_speed >= 30; SELECT user_settings::JSONB || '{"badge": "Helmsman"}'::JSONB into user_settings;
-- Club Alaska -- Send notification
-- todo country zone PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
-- Tropical Traveler end if;
-- todo country zone end if;
-- Aloha Award
-- todo pacific zone -- Wake Maker = windspeeds above 15kts
-- TODO the sea is big and the world is not limited to the US SELECT (preferences->'badges'->'Wake Maker') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
END RAISE WARNING '-> Wake Maker %', _exist;
$process_badge_queue$ language plpgsql; if _exist is false then
-- is 15 knot+ logbook?
select l.max_wind_speed into max_wind_speed from api.logbook l where l.id = logbook_id AND l.max_wind_speed >= 15 and client_id = current_setting('vessel.client_id', false);
--RAISE WARNING '-> Wake Maker max_wind_speed %', max_wind_speed;
if max_wind_speed >= 15 then
-- Create badge
badge := '{"Wake Maker": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
--RAISE WARNING '-> Wake Maker max_wind_speed badge %', badge;
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
--RAISE WARNING '-> Wake Maker max_wind_speed badge % %', badge, _badges;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Wake Maker"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
-- Stormtrooper = windspeeds above 30kts
SELECT (preferences->'badges'->'Stormtrooper') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
--RAISE WARNING '-> Stormtrooper %', _exist;
select l.max_wind_speed into max_wind_speed from api.logbook l where l.id = logbook_id AND l.max_wind_speed >= 30 and client_id = current_setting('vessel.client_id', false);
--RAISE WARNING '-> Stormtrooper max_wind_speed %', max_wind_speed;
if max_wind_speed >= 30 then
-- Create badge
badge := '{"Stormtrooper": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
--RAISE WARNING '-> Stormtrooper max_wind_speed badge %', badge;
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- RAISE WARNING '-> Wake Maker max_wind_speed badge % %', badge, _badges;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Stormtrooper"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
-- Navigator Award = one logbook with distance over 100NM
SELECT (preferences->'badges'->'Navigator Award') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
select l.distance into distance from api.logbook l where l.id = logbook_id AND l.distance >= 100 and client_id = current_setting('vessel.client_id', false);
if distance >= 100 then
-- Create badge
badge := '{"Navigator Award": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Navigator Award"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
-- Captain Award = total logbook distance over 1000NM
SELECT (preferences->'badges'->'Captain Award') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
select sum(l.distance) into distance from api.logbook l where client_id = current_setting('vessel.client_id', false);
if distance >= 1000 then
-- Create badge
badge := '{"Captain Award": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Captain Award"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
END;
$badges_logbook$ LANGUAGE plpgsql;
-- Description
COMMENT ON FUNCTION
public.badges_logbook_fn
IS 'check for new badges, eg: Helmsman, Wake Maker, Stormtrooper';
CREATE OR REPLACE FUNCTION public.badges_moorages_fn() RETURNS VOID AS $badges_moorages$
DECLARE
_badges jsonb;
_exist BOOLEAN := false;
duration integer;
badge text;
user_settings jsonb;
BEGIN
-- Check and set environment
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
PERFORM set_config('user.email', user_settings->>'email'::TEXT, false);
-- Explorer = 10 days away from home port
SELECT (preferences->'badges'->'Explorer') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
--select sum(m.stay_duration) from api.moorages m where home_flag is false;
SELECT extract(day from (select sum(m.stay_duration) INTO duration FROM api.moorages m WHERE home_flag IS false AND client_id = current_setting('vessel.client_id', false) ));
if duration >= 10 then
-- Create badge
badge := '{"Explorer": {"date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Explorer"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
-- Mooring Pro = 10 nights on buoy!
SELECT (preferences->'badges'->'Mooring Pro') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
-- select sum(m.stay_duration) from api.moorages m where stay_code = 3;
SELECT extract(day from (select sum(m.stay_duration) INTO duration FROM api.moorages m WHERE stay_code = 3 AND client_id = current_setting('vessel.client_id', false) ));
if duration >= 10 then
-- Create badge
badge := '{"Mooring Pro": {"date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Mooring Pro"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
-- Anchormaster = 25 days on anchor
SELECT (preferences->'badges'->'Anchormaster') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
if _exist is false then
-- select sum(m.stay_duration) from api.moorages m where stay_code = 2;
SELECT extract(day from (select sum(m.stay_duration) INTO duration FROM api.moorages m WHERE stay_code = 2 AND client_id = current_setting('vessel.client_id', false) ));
if duration >= 25 then
-- Create badge
badge := '{"Anchormaster": {"date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) into badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
-- Gather user settings
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || '{"badge": "Anchormaster"}'::JSONB into user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
end if;
END;
$badges_moorages$ LANGUAGE plpgsql;
-- Description
COMMENT ON FUNCTION
public.badges_moorages_fn
IS 'check moorages for new badges, eg: Explorer, Mooring Pro, Anchormaster';
CREATE OR REPLACE FUNCTION public.badges_geom_fn(IN logbook_id integer) RETURNS VOID AS $badges_geom$
DECLARE
_badges jsonb;
_exist BOOLEAN := false;
badge text;
marine_rec record;
user_settings jsonb;
badge_tmp text;
begin
RAISE WARNING '--> user.email [%], vessel.client_id [%]', current_setting('user.email', false), current_setting('vessel.client_id', false);
-- Tropical & Alaska zone manualy add into ne_10m_geography_marine_polys
-- Check if each geographic marine zone exist as a badge
FOR marine_rec IN
WITH log AS (
SELECT l.track_geom AS track_geom FROM api.logbook l
WHERE l.id = logbook_id AND client_id = current_setting('vessel.client_id', false)
)
SELECT name from log, public.ne_10m_geography_marine_polys
WHERE ST_Intersects(
geom, -- ST_SetSRID(geom,4326),
log.track_geom
)
LOOP
-- If not generate and insert the new bagde
--RAISE WARNING 'geography_marine [%]', marine_rec.name;
SELECT jsonb_extract_path(a.preferences, 'badges', marine_rec.name) IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
--RAISE WARNING 'geography_marine [%]', _exist;
if _exist is false then
-- Create badge
badge := '{"' || marine_rec.name || '": {"log": '|| logbook_id ||', "date":"' || NOW()::timestamp || '"}}';
-- Get existing badges
SELECT preferences->'badges' INTO _badges FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
-- Merge badges
SELECT public.jsonb_recursive_merge(badge::jsonb, _badges::jsonb) INTO badge;
-- Update badges for user
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
--RAISE WARNING '--> badges_geom_fn [%]', badge;
-- Gather user settings
badge_tmp := '{"badge": "' || marine_rec.name || '"}';
user_settings := get_user_settings_from_clientid_fn(current_setting('vessel.client_id', false));
SELECT user_settings::JSONB || badge_tmp::JSONB INTO user_settings;
-- Send notification
PERFORM send_notification_fn('badge'::TEXT, user_settings::JSONB);
end if;
END LOOP;
END;
$badges_geom$ LANGUAGE plpgsql;
-- Description
COMMENT ON FUNCTION
public.badges_geom_fn
IS 'check geometry logbook for new badges, eg: Tropic, Alaska, Geographic zone';
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
-- TODO add alert monitoring for Battery -- TODO add alert monitoring for Battery
@@ -849,6 +1094,11 @@ BEGIN
--RAISE WARNING 'jwt email %', current_setting('request.jwt.claims', true)::json->>'email'; --RAISE WARNING 'jwt email %', current_setting('request.jwt.claims', true)::json->>'email';
--RAISE WARNING 'jwt role %', current_setting('request.jwt.claims', true)::json->>'role'; --RAISE WARNING 'jwt role %', current_setting('request.jwt.claims', true)::json->>'role';
--RAISE WARNING 'cur_user %', current_user; --RAISE WARNING 'cur_user %', current_user;
--TODO SELECT current_setting('request.jwt.uid', true)::json->>'uid' INTO _user_id;
--TODO RAISE WARNING 'jwt user_id %', current_setting('request.jwt.uid', true)::json->>'uid';
--TODO SELECT current_setting('request.jwt.vid', true)::json->>'vid' INTO _vessel_id;
--TODO RAISE WARNING 'jwt vessel_id %', current_setting('request.jwt.vid', true)::json->>'vid';
IF _role = 'user_role' THEN IF _role = 'user_role' THEN
-- Check the user exist in the accounts table -- Check the user exist in the accounts table
SELECT * INTO account_rec SELECT * INTO account_rec
@@ -898,7 +1148,7 @@ BEGIN
WHERE WHERE
m.vessel_id = current_setting('vessel.id') m.vessel_id = current_setting('vessel.id')
AND m.vessel_id = v.vessel_id AND m.vessel_id = v.vessel_id
AND v.owner_email =_email; AND v.owner_email = _email;
-- Set session variables -- Set session variables
PERFORM set_config('vessel.client_id', _clientid, false); PERFORM set_config('vessel.client_id', _clientid, false);
--RAISE WARNING 'public.check_jwt() user_role vessel.client_id [%]', current_setting('vessel.client_id', false); --RAISE WARNING 'public.check_jwt() user_role vessel.client_id [%]', current_setting('vessel.client_id', false);

View File

@@ -345,10 +345,10 @@ $urlencode_py$ LANGUAGE plpython3u IMMUTABLE STRICT;
-- python -- python
-- https://ipapi.co/ -- https://ipapi.co/
DROP FUNCTION IF EXISTS reverse_geoip_py_fn; DROP FUNCTION IF EXISTS reverse_geoip_py_fn;
CREATE OR REPLACE FUNCTION reverse_geoip_py_fn(IN _ip TEXT) RETURNS void CREATE OR REPLACE FUNCTION reverse_geoip_py_fn(IN _ip TEXT) RETURNS JSONB
AS $reverse_geoip_py$ AS $reverse_geoip_py$
""" """
TODO Return ipapi.co ip details
""" """
import requests import requests
import json import json
@@ -358,13 +358,15 @@ AS $reverse_geoip_py$
r = requests.get(url) r = requests.get(url)
#print(r.text) #print(r.text)
# Return something boolean? # Return something boolean?
#plpy.notice('Sent successfully to [{}] [{}]'.format(r.text, r.status_code)) #plpy.notice('IP [{}] [{}]'.format(_ip, r.status_code))
if r.status_code == 200: if r.status_code == 200:
plpy.notice('Sent successfully to [{}] [{}]'.format(r.text, r.status_code)) #plpy.notice('Got [{}] [{}]'.format(r.text, r.status_code))
return r.text;
else: else:
plpy.error('Failed to send') plpy.error('Failed to get ip details')
return None return '{}'
$reverse_geoip_py$ TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u; $reverse_geoip_py$ LANGUAGE plpython3u;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
public.reverse_geoip_py_fn public.reverse_geoip_py_fn
@@ -403,6 +405,8 @@ AS $geojson_py$
#plpy.notice(feature) #plpy.notice(feature)
if (feature['geometry']['type'] != geometry_type): if (feature['geometry']['type'] != geometry_type):
output.append(feature) output.append(feature)
#elif (feature['properties']['id']): TODO
# output.append(feature)
#else: #else:
# plpy.notice('ignoring') # plpy.notice('ignoring')
return json.dumps(output) return json.dumps(output)

View File

@@ -58,7 +58,7 @@ COMMENT ON TRIGGER accounts_moddatetime
DROP TABLE IF EXISTS auth.vessels; DROP TABLE IF EXISTS auth.vessels;
CREATE TABLE IF NOT EXISTS auth.vessels ( CREATE TABLE IF NOT EXISTS auth.vessels (
vessel_id TEXT NOT NULL UNIQUE DEFAULT RIGHT(gen_random_uuid()::text, 12), vessel_id TEXT NOT NULL UNIQUE DEFAULT RIGHT(gen_random_uuid()::text, 12),
-- user_id REFERENCES auth.accounts(user_id) ON DELETE RESTRICT, -- user_id TEXT NOT NULL REFERENCES auth.accounts(user_id) ON DELETE RESTRICT,
owner_email CITEXT PRIMARY KEY REFERENCES auth.accounts(email) ON DELETE RESTRICT, owner_email CITEXT PRIMARY KEY REFERENCES auth.accounts(email) ON DELETE RESTRICT,
-- mmsi TEXT UNIQUE, -- Should be a numeric range between 100000000 and 800000000. -- mmsi TEXT UNIQUE, -- Should be a numeric range between 100000000 and 800000000.
mmsi NUMERIC UNIQUE, -- MMSI can be optional but if present must be a valid one and unique mmsi NUMERIC UNIQUE, -- MMSI can be optional but if present must be a valid one and unique
@@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS auth.vessels (
-- Description -- Description
COMMENT ON TABLE COMMENT ON TABLE
auth.vessels auth.vessels
IS 'vessels table link to accounts email column'; IS 'vessels table link to accounts email user_id column';
-- Indexes -- Indexes
CREATE INDEX vessels_role_idx ON auth.vessels (role); CREATE INDEX vessels_role_idx ON auth.vessels (role);
CREATE INDEX vessels_name_idx ON auth.vessels (name); CREATE INDEX vessels_name_idx ON auth.vessels (name);
@@ -174,6 +174,7 @@ declare
app_jwt_secret text; app_jwt_secret text;
_email_valid boolean := false; _email_valid boolean := false;
_email text := email; _email text := email;
_user_id text := null;
begin begin
-- check email and password -- check email and password
select auth.user_role(email, pass) into _role; select auth.user_role(email, pass) into _role;
@@ -187,7 +188,7 @@ begin
WHERE name = 'app.jwt_secret'; WHERE name = 'app.jwt_secret';
-- Check email_valid and generate OTP -- Check email_valid and generate OTP
SELECT preferences['email_valid'] INTO _email_valid SELECT preferences['email_valid'],user_id INTO _email_valid,_user_id
FROM auth.accounts a FROM auth.accounts a
WHERE a.email = _email; WHERE a.email = _email;
IF _email_valid is null or _email_valid is False THEN IF _email_valid is null or _email_valid is False THEN
@@ -202,7 +203,8 @@ begin
row_to_json(r)::json, app_jwt_secret row_to_json(r)::json, app_jwt_secret
) as token ) as token
from ( from (
select _role as role, login.email as email, select _role as role, login.email as email, -- TODO replace with user_id
-- select _role as role, user_id as uid,
extract(epoch from now())::integer + 60*60 as exp extract(epoch from now())::integer + 60*60 as exp
) r ) r
into result; into result;
@@ -275,7 +277,8 @@ begin
) as token ) as token
from ( from (
select vessel_rec.role as role, select vessel_rec.role as role,
vessel_rec.owner_email as email, vessel_rec.owner_email as email, -- TODO replace with user_id
-- vessel_rec.user_id as uid
vessel_rec.vessel_id as vid vessel_rec.vessel_id as vid
) r ) r
into result; into result;

View File

@@ -12,6 +12,15 @@ select current_database();
ALTER TABLE api.metadata ADD vessel_id TEXT NOT NULL REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT; ALTER TABLE api.metadata ADD vessel_id TEXT NOT NULL REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT;
COMMENT ON COLUMN api.metadata.vessel_id IS 'Link auth.vessels with api.metadata'; COMMENT ON COLUMN api.metadata.vessel_id IS 'Link auth.vessels with api.metadata';
-- Link auth.vessels with auth.accounts
--ALTER TABLE auth.vessels ADD user_id TEXT NOT NULL REFERENCES auth.accounts(user_id) ON DELETE RESTRICT;
--COMMENT ON COLUMN auth.vessels.user_id IS 'Link auth.vessels with auth.accounts';
--COMMENT ON COLUMN auth.vessels.vessel_id IS 'Vessel identifier. Link auth.vessels with api.metadata';
-- REFERENCE ship type with AIS type ?
-- REFERENCE mmsi MID with country ?
-- List vessel -- List vessel
--TODO add geojson with position --TODO add geojson with position
DROP VIEW IF EXISTS api.vessels_view; DROP VIEW IF EXISTS api.vessels_view;
@@ -60,42 +69,37 @@ COMMENT ON FUNCTION
DROP FUNCTION IF EXISTS api.vessel_fn; DROP FUNCTION IF EXISTS api.vessel_fn;
CREATE OR REPLACE FUNCTION api.vessel_fn(OUT vessel JSON) RETURNS JSON CREATE OR REPLACE FUNCTION api.vessel_fn(OUT vessel JSON) RETURNS JSON
AS $vessel$ AS $vessel$
DECLARE DECLARE
BEGIN BEGIN
SELECT SELECT
json_build_object( jsonb_build_object(
'name', v.name, 'name', v.name,
'mmsi', coalesce(v.mmsi, null), 'mmsi', coalesce(v.mmsi, null),
'created_at', v.created_at::timestamp(0), 'created_at', v.created_at::timestamp(0),
'last_contact', coalesce(m.time, null), 'last_contact', coalesce(m.time, null),
'geojson', coalesce(ST_AsGeoJSON(geojson_t.*)::json, null) 'geojson', coalesce(ST_AsGeoJSON(geojson_t.*)::json, null)
) )::jsonb || api.vessel_details_fn()::jsonb
INTO vessel INTO vessel
FROM auth.vessels v, api.metadata m, FROM auth.vessels v, api.metadata m,
( SELECT ( select
t.* current_setting('vessel.name') as name,
FROM ( time,
( select courseovergroundtrue,
current_setting('vessel.name') as name, speedoverground,
time, anglespeedapparent,
courseovergroundtrue, longitude,latitude,
speedoverground, st_makepoint(longitude,latitude) AS geo_point
anglespeedapparent, FROM api.metrics
longitude,latitude, WHERE
st_makepoint(longitude,latitude) AS geo_point latitude IS NOT NULL
FROM api.metrics AND longitude IS NOT NULL
WHERE AND client_id = current_setting('vessel.client_id', false)
latitude IS NOT NULL ORDER BY time DESC
AND longitude IS NOT NULL ) AS geojson_t
AND client_id = current_setting('vessel.client_id', false)
ORDER BY time DESC
)
) AS t
) AS geojson_t
WHERE WHERE
m.vessel_id = current_setting('vessel.id') m.vessel_id = current_setting('vessel.id')
AND m.vessel_id = v.vessel_id; AND m.vessel_id = v.vessel_id;
--RAISE notice 'api.vessel_fn %', obj; --RAISE notice 'api.vessel_fn %', obj;
END; END;
$vessel$ language plpgsql security definer; $vessel$ language plpgsql security definer;
-- Description -- Description
@@ -126,16 +130,18 @@ COMMENT ON FUNCTION
DROP FUNCTION IF EXISTS api.versions_fn; DROP FUNCTION IF EXISTS api.versions_fn;
CREATE OR REPLACE FUNCTION api.versions_fn() RETURNS JSON CREATE OR REPLACE FUNCTION api.versions_fn() RETURNS JSON
AS $version$ AS $version$
DECLARE DECLARE
_appv TEXT; _appv TEXT;
_sysv TEXT; _sysv TEXT;
BEGIN BEGIN
SELECT SELECT
value, rtrim(substring(version(), 0, 17)) AS sys_version into _appv,_sysv value, rtrim(substring(version(), 0, 17)) AS sys_version into _appv,_sysv
FROM app_settings FROM app_settings
WHERE name = 'app.version'; WHERE name = 'app.version';
RETURN json_build_object('api_version', _appv, RETURN json_build_object('api_version', _appv,
'sys_version', _sysv); 'sys_version', _sysv,
'timescaledb', (SELECT extversion as timescaledb FROM pg_extension WHERE extname='timescaledb'),
'postgis', (SELECT extversion as postgis FROM pg_extension WHERE extname='postgis'));
END; END;
$version$ language plpgsql security definer; $version$ language plpgsql security definer;
-- Description -- Description
@@ -193,3 +199,27 @@ $update_user_preferences$ language plpgsql security definer;
COMMENT ON FUNCTION COMMENT ON FUNCTION
api.update_user_preferences_fn api.update_user_preferences_fn
IS 'Update user preferences jsonb key pair value'; IS 'Update user preferences jsonb key pair value';
DROP FUNCTION IF EXISTS api.vessel_details_fn;
CREATE OR REPLACE FUNCTION api.vessel_details_fn() RETURNS JSON AS
$vessel_details$
DECLARE
BEGIN
RETURN ( WITH tbl AS (
SELECT mmsi,ship_type,length,beam,height FROM api.metadata WHERE client_id = current_setting('vessel.client_id', false)
)
SELECT json_build_object(
'ship_type', (SELECT ais.description FROM aistypes ais, tbl WHERE t.ship_type = ais.id),
'country', (SELECT mid.country FROM mid, tbl WHERE LEFT(cast(mmsi as text), 3)::NUMERIC = mid.id),
'alpha_2', (SELECT o.alpha_2 FROM mid m, iso3166 o, tbl WHERE LEFT(cast(mmsi as text), 3)::NUMERIC = m.id AND m.country_id = o.id),
'length', t.ship_type,
'beam', t.beam,
'height', t.height)
FROM tbl t
);
END;
$vessel_details$ language plpgsql security definer;
-- Description
COMMENT ON FUNCTION
api.vessel_details_fn
IS 'Return vessel details such as metadata (length,beam,height), ais type and country name and country iso3166-alpha-2';

View File

@@ -83,7 +83,7 @@ AS $recover_fn$
DECLARE DECLARE
_email CITEXT := email; _email CITEXT := email;
_user_id TEXT := NULL; _user_id TEXT := NULL;
otp_pass VARCHAR(10) := NULL; otp_pass TEXT := NULL;
_reset_qs TEXT := NULL; _reset_qs TEXT := NULL;
user_settings jsonb := NULL; user_settings jsonb := NULL;
BEGIN BEGIN
@@ -96,9 +96,8 @@ AS $recover_fn$
RAISE EXCEPTION 'Invalid input' RAISE EXCEPTION 'Invalid input'
USING HINT = 'Check your parameter'; USING HINT = 'Check your parameter';
END IF; END IF;
-- OTP Code -- Generate OTP
SELECT generate_uid_fn(6) INTO otp_pass; otp_pass := api.generate_otp_fn(email);
INSERT INTO auth.otp (user_email, otp_pass) VALUES (_email, otp_pass);
SELECT CONCAT('uuid=', _user_id, '&token=', otp_pass) INTO _reset_qs; SELECT CONCAT('uuid=', _user_id, '&token=', otp_pass) INTO _reset_qs;
-- Send email/notifications -- Send email/notifications
user_settings := '{"email": "' || _email || '", "reset_qs": "' || _reset_qs || '"}'; user_settings := '{"email": "' || _email || '", "reset_qs": "' || _reset_qs || '"}';
@@ -232,7 +231,7 @@ AS $email_validation$
-- Send Notification async -- Send Notification async
--INSERT INTO process_queue (channel, payload, stored) --INSERT INTO process_queue (channel, payload, stored)
-- VALUES ('email_valid', _email, now()); -- VALUES ('email_valid', _email, now());
RETURN True; RETURN True;
END IF; END IF;
RETURN False; RETURN False;
END; END;
@@ -276,7 +275,7 @@ AS $pushover_subscribe_link$
name = 'app.pushover_app_url'; name = 'app.pushover_app_url';
-- Generate OTP -- Generate OTP
otp_code := api.generate_otp_fn(email); otp_code := api.generate_otp_fn(email);
-- On sucess redirect to API endpoint -- On success redirect to API endpoint
SELECT CONCAT( SELECT CONCAT(
'?success=', '?success=',
public.urlescape_py_fn(CONCAT(app_url,'/pushover?token=')), public.urlescape_py_fn(CONCAT(app_url,'/pushover?token=')),
@@ -322,7 +321,7 @@ AS $pushover$
DELETE FROM auth.otp DELETE FROM auth.otp
WHERE user_email = _email; WHERE user_email = _email;
-- Disable Notification because -- Disable Notification because
-- Pushover send a notificataion when sucesssfull with the description of the app -- Pushover send a notification when sucesssful with the description of the app
-- --
-- Send Notification async -- Send Notification async
--INSERT INTO process_queue (channel, payload, stored) --INSERT INTO process_queue (channel, payload, stored)
@@ -335,16 +334,15 @@ $pushover$ language plpgsql security definer;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
api.pushover_fn api.pushover_fn
IS 'Confirm Pushover Subscription and store pushover_user_key into user preferences if valid token/otp'; IS 'Confirm Pushover Subscription and store pushover_user_key into user preferences if provide a valid OTP token';
-- Telegram OTP Validation -- Telegram OTP Validation
-- Expose as an API endpoint -- Expose as an API endpoint
DROP FUNCTION IF EXISTS api.telegram_fn; DROP FUNCTION IF EXISTS api.telegram_fn;
CREATE OR REPLACE FUNCTION api.telegram_fn(IN token TEXT, IN telegram_obj TEXT) RETURNS BOOLEAN CREATE OR REPLACE FUNCTION api.telegram_fn(IN token TEXT, IN telegram_obj TEXT) RETURNS BOOLEAN
AS $telegram$ AS $telegram$
DECLARE DECLARE
_email TEXT := NULL; _email TEXT := NULL;
_updated BOOLEAN := False;
user_settings jsonb; user_settings jsonb;
BEGIN BEGIN
-- Check parameters -- Check parameters
@@ -357,14 +355,14 @@ AS $telegram$
-- Set user email into env to allow RLS update -- Set user email into env to allow RLS update
PERFORM set_config('user.email', _email, false); PERFORM set_config('user.email', _email, false);
-- Add telegram obj into user preferences -- Add telegram obj into user preferences
SELECT api.update_user_preferences_fn('{telegram}'::TEXT, telegram_obj::TEXT) INTO _updated; PERFORM api.update_user_preferences_fn('{telegram}'::TEXT, telegram_obj::TEXT);
-- Delete token when validated -- Delete token when validated
DELETE FROM auth.otp DELETE FROM auth.otp
WHERE user_email = _email; WHERE user_email = _email;
-- Send Notification async -- Send Notification async
INSERT INTO process_queue (channel, payload, stored) INSERT INTO process_queue (channel, payload, stored)
VALUES ('telegram_valid', _email, now()); VALUES ('telegram_valid', _email, now());
RETURN _updated; RETURN True;
END IF; END IF;
RETURN False; RETURN False;
END; END;
@@ -372,15 +370,15 @@ $telegram$ language plpgsql security definer;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
api.telegram_fn api.telegram_fn
IS 'Confirm telegram user and store telegram chat details into user preferences if valid token/otp'; IS 'Confirm telegram user and store telegram chat details into user preferences if provide a valid OTP token';
-- Telegram user validation -- Telegram user validation
DROP FUNCTION IF EXISTS auth.telegram_user_exists_fn; DROP FUNCTION IF EXISTS auth.telegram_user_exists_fn;
CREATE OR REPLACE FUNCTION auth.telegram_user_exists_fn(IN email TEXT, IN user_id BIGINT) RETURNS BOOLEAN CREATE OR REPLACE FUNCTION auth.telegram_user_exists_fn(IN email TEXT, IN user_id BIGINT) RETURNS BOOLEAN
AS $telegram_user_exists$ AS $telegram_user_exists$
DECLARE DECLARE
_email CITEXT := email; _email CITEXT := email;
_user_id BIGINT := user_id; _user_id BIGINT := user_id;
BEGIN BEGIN
IF _email IS NULL OR _chat_id IS NULL THEN IF _email IS NULL OR _chat_id IS NULL THEN
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter'; RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
@@ -389,7 +387,7 @@ AS $telegram_user_exists$
SELECT preferences->'telegram'->'from'->'id' INTO _user_id SELECT preferences->'telegram'->'from'->'id' INTO _user_id
FROM auth.accounts a FROM auth.accounts a
WHERE a.email = _email WHERE a.email = _email
AND cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT; AND cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT;
IF FOUND THEN IF FOUND THEN
RETURN TRUE; RETURN TRUE;
END IF; END IF;
@@ -399,22 +397,22 @@ $telegram_user_exists$ language plpgsql security definer;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
auth.telegram_user_exists_fn auth.telegram_user_exists_fn
IS 'Check if user exist based on email and telegram obj preferences'; IS 'Check if user exist based on email and user_id';
-- Telegram otp validation -- Telegram otp validation
DROP FUNCTION IF EXISTS auth.telegram_otp_fn; DROP FUNCTION IF EXISTS api.telegram_otp_fn;
CREATE OR REPLACE FUNCTION auth.telegram_otp_fn(IN email TEXT, OUT otp_code TEXT) RETURNS TEXT CREATE OR REPLACE FUNCTION api.telegram_otp_fn(IN email TEXT, OUT otp_code TEXT) RETURNS TEXT
AS $telegram_otp$ AS $telegram_otp$
DECLARE DECLARE
_email CITEXT := email; _email CITEXT := email;
user_settings jsonb := NULL; user_settings jsonb := NULL;
BEGIN BEGIN
IF _email IS NULL THEN IF _email IS NULL THEN
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter'; RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
END IF; END IF;
-- Generate token -- Generate token
otp_code := api.generate_otp_fn(_email); otp_code := api.generate_otp_fn(_email);
IF otp_code IS NOT NULL THEN IF otp_code IS NOT NULL THEN
-- Set user email into env to allow RLS update -- Set user email into env to allow RLS update
PERFORM set_config('user.email', _email, false); PERFORM set_config('user.email', _email, false);
-- Send Notification -- Send Notification
@@ -425,30 +423,38 @@ AS $telegram_otp$
$telegram_otp$ language plpgsql security definer; $telegram_otp$ language plpgsql security definer;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
auth.telegram_otp_fn api.telegram_otp_fn
IS 'TODO'; IS 'Telegram otp generation';
-- Telegram bot JWT auth -- Telegram JWT auth
-- Expose as an API endpoint -- Expose as an API endpoint
-- Avoid sending a password so use email and chat_id as key pair -- Avoid sending a password so use email and chat_id as key pair
DROP FUNCTION IF EXISTS api.bot(text,BIGINT); DROP FUNCTION IF EXISTS api.telegram;
CREATE OR REPLACE FUNCTION api.bot(IN email TEXT, IN user_id BIGINT) RETURNS auth.jwt_token CREATE OR REPLACE FUNCTION api.telegram(IN user_id BIGINT, IN email TEXT DEFAULT NULL) RETURNS auth.jwt_token
AS $telegram_bot$ AS $telegram_jwt$
DECLARE DECLARE
_email TEXT := email; _email TEXT := email;
_user_id BIGINT := user_id; _user_id BIGINT := user_id;
_uid TEXT := NULL;
_exist BOOLEAN := False; _exist BOOLEAN := False;
result auth.jwt_token; result auth.jwt_token;
app_jwt_secret text; app_jwt_secret text;
BEGIN BEGIN
IF _email IS NULL OR _chat_id IS NULL THEN IF _user_id IS NULL THEN
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter'; RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
END IF; END IF;
-- check email and _chat_id
select auth.telegram_user_exists_fn(_email, _user_id) into _exist; -- Check _user_id
if _exist is null or _exist <> True then SELECT auth.telegram_session_exists_fn(_user_id) into _exist;
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter'; IF _exist IS NULL OR _exist <> True THEN
end if; --RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
RETURN NULL;
END IF;
-- Get email and user_id
SELECT a.email,a.user_id INTO _email,_uid
FROM auth.accounts a
WHERE cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT;
-- Get app_jwt_secret -- Get app_jwt_secret
SELECT value INTO app_jwt_secret SELECT value INTO app_jwt_secret
@@ -460,28 +466,30 @@ AS $telegram_bot$
row_to_json(r)::json, app_jwt_secret row_to_json(r)::json, app_jwt_secret
) as token ) as token
from ( from (
select 'user_role' as role, select 'user_role' as role,
(select lower(_email)) as email, (select lower(_email)) as email,
_uid as uid,
extract(epoch from now())::integer + 60*60 as exp extract(epoch from now())::integer + 60*60 as exp
) r ) r
into result; into result;
return result; return result;
END; END;
$telegram_bot$ language plpgsql security definer; $telegram_jwt$ language plpgsql security definer;
-- Description -- Description
COMMENT ON FUNCTION COMMENT ON FUNCTION
api.bot api.telegram
IS 'Generate a JWT user_role token from email for telegram bot'; IS 'Generate a JWT user_role token based on chat_id from telegram';
-- Telegram chat_id Session validation -- Telegram chat_id session validation
DROP FUNCTION IF EXISTS auth.telegram_session_exists_fn; DROP FUNCTION IF EXISTS auth.telegram_session_exists_fn;
CREATE OR REPLACE FUNCTION auth.telegram_session_exists_fn(IN user_id BIGINT) RETURNS BOOLEAN CREATE OR REPLACE FUNCTION auth.telegram_session_exists_fn(IN user_id BIGINT) RETURNS BOOLEAN
AS $telegram_session_exists$ AS $telegram_session_exists$
DECLARE DECLARE
_id TEXT := NULL; _id BIGINT := NULL;
_user_id BIGINT := user_id; _user_id BIGINT := user_id;
_email TEXT := NULL;
BEGIN BEGIN
IF _chat_id IS NULL THEN IF user_id IS NULL THEN
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter'; RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
END IF; END IF;
@@ -489,10 +497,10 @@ AS $telegram_session_exists$
SELECT preferences->'telegram'->'from'->'id' INTO _id SELECT preferences->'telegram'->'from'->'id' INTO _id
FROM auth.accounts a FROM auth.accounts a
WHERE cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT; WHERE cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT;
IF NOT FOUND then IF FOUND THEN
RETURN False; RETURN True;
END IF; END IF;
RETURN True; RETURN FALSE;
END; END;
$telegram_session_exists$ language plpgsql security definer; $telegram_session_exists$ language plpgsql security definer;
-- Description -- Description

View File

@@ -30,12 +30,14 @@ grant execute on function api.recover(text) to api_anonymous;
grant execute on function api.reset(text,text,text) to api_anonymous; grant execute on function api.reset(text,text,text) to api_anonymous;
-- explicitly limit EXECUTE privileges to pgrest db-pre-request function -- explicitly limit EXECUTE privileges to pgrest db-pre-request function
grant execute on function public.check_jwt() to api_anonymous; grant execute on function public.check_jwt() to api_anonymous;
-- explicitly limit EXECUTE privileges to only telegram bot auth function -- explicitly limit EXECUTE privileges to only telegram jwt auth function
grant execute on function api.bot(text,bigint) to api_anonymous; grant execute on function api.telegram(bigint,text) to api_anonymous;
-- explicitly limit EXECUTE privileges to only pushover subscription validation function -- explicitly limit EXECUTE privileges to only pushover subscription validation function
grant execute on function api.email_fn(text) to api_anonymous; grant execute on function api.email_fn(text) to api_anonymous;
grant execute on function api.pushover_fn(text,text) to api_anonymous; grant execute on function api.pushover_fn(text,text) to api_anonymous;
grant execute on function api.telegram_fn(text,text) to api_anonymous; grant execute on function api.telegram_fn(text,text) to api_anonymous;
grant execute on function api.telegram_otp_fn(text) to api_anonymous;
--grant execute on function api.generate_otp_fn(text) to api_anonymous;
-- authenticator -- authenticator
-- login role -- login role

View File

@@ -1 +1 @@
0.0.11 0.1.0