13 Commits

Author SHA1 Message Date
xbgmsharp
22466430ac Release v0.6.1 2024-01-30 22:48:46 +01:00
xbgmsharp
643c16ad3f Update keycloak account status 2024-01-30 22:48:22 +01:00
xbgmsharp
59a3c41b4a Update grafana cron, Add keycloak provisioning to sync vessel_id as user attributs 2024-01-30 22:33:08 +01:00
xbgmsharp
371eb6c720 Update message template. Update grafana notification 2024-01-30 22:32:28 +01:00
xbgmsharp
c2ffe9777c Update get_app_settings_fn, add keycloak URI 2024-01-30 22:31:53 +01:00
xbgmsharp
c0261791f5 Add keycloak python user integration 2024-01-30 21:55:30 +01:00
xbgmsharp
e727954f83 Update api.vessel_details_fn, fix length 2024-01-29 21:45:26 +01:00
xbgmsharp
22b04334f8 Udpatr frontend, dump 0.0.9-beta3 2024-01-26 16:33:42 +01:00
xbgmsharp
a5ec4c0039 Update monitoring_view, remove status 2024-01-26 13:05:44 +01:00
xbgmsharp
6a63f7d02f Update cron comment, Add deprecated comment 2024-01-26 11:32:50 +01:00
xbgmsharp
2fec2e650c Update frontend to latest beta 2024-01-26 11:32:05 +01:00
xbgmsharp
ed8514bfb1 Update Grafana default dashboard. Update uuid for provisioning.
Fix metric order to get display the latest know vessel position vs the first one
2024-01-26 11:31:08 +01:00
xbgmsharp
f25e735674 Update overpass_py return jsonb versus a string when there is no value 2024-01-22 21:55:38 +01:00
16 changed files with 121 additions and 35 deletions

View File

@@ -1689,7 +1689,7 @@
},
"timezone": "utc",
"title": "Electrical System",
"uid": "rk0FTiIMk",
"uid": "pgsail_tpl_electrical",
"version": 11,
"weekStart": ""
}

View File

@@ -466,7 +466,7 @@
"timepicker": {},
"timezone": "utc",
"title": "Logbook",
"uid": "E_FUkx9nk",
"uid": "pgsail_tpl_logbook",
"version": 1,
"weekStart": ""
}

View File

@@ -732,7 +732,7 @@
},
"timezone": "utc",
"title": "Monitor",
"uid": "apqDcPjMz",
"uid": "pgsail_tpl_monitor",
"version": 1,
"weekStart": ""
}

View File

@@ -1335,7 +1335,7 @@
},
"timezone": "",
"title": "RPI System",
"uid": "4kxYm6j7k",
"uid": "pgsail_tpl_rpi",
"version": 1,
"weekStart": ""
}

View File

@@ -629,7 +629,7 @@
},
"timezone": "utc",
"title": "Solar System",
"uid": "62bzzlr7z",
"uid": "pgsail_tpl_solar",
"version": 1,
"weekStart": ""
}

View File

@@ -1981,7 +1981,7 @@
},
"timezone": "utc",
"title": "Weather",
"uid": "631a97c2e",
"uid": "pgsail_tpl_weather",
"version": 1,
"weekStart": ""
}

View File

@@ -204,7 +204,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
"rawSql": "SELECT latitude, longitude FROM api.metrics WHERE vessel_id = '${boat}' ORDER BY time ASC LIMIT 1;",
"rawSql": "SELECT latitude, longitude FROM api.metrics WHERE vessel_id = '${boat}' ORDER BY time DESC LIMIT 1;",
"refId": "A",
"sql": {
"columns": [
@@ -291,7 +291,7 @@
},
"timezone": "browser",
"title": "Home",
"uid": "d81aa15b",
"uid": "pgsail_tpl_home",
"version": 1,
"weekStart": ""
}
}

View File

@@ -397,8 +397,8 @@ CREATE VIEW api.monitoring_view WITH (security_invoker=true,security_barrier=tru
'speedoverground', m.speedoverground,
'windspeedapparent', m.windspeedapparent
)::jsonb ) AS geojson,
current_setting('vessel.name', false) AS name,
( SELECT api.status_fn() ) AS status
current_setting('vessel.name', false) AS name
--( SELECT api.status_fn() ) AS status
FROM api.metrics m
ORDER BY time DESC LIMIT 1;
COMMENT ON VIEW

View File

@@ -124,7 +124,7 @@ $$ language plpgsql;
-- Description
COMMENT ON FUNCTION
public.cron_process_new_moorage_fn
IS 'init by pg_cron to check for new moorage pending update, if so perform process_moorage_queue_fn';
IS 'Deprecated, init by pg_cron to check for new moorage pending update, if so perform process_moorage_queue_fn';
-- CRON Monitor offline pending notification
create function cron_process_monitor_offline_fn() RETURNS void AS $$
@@ -388,6 +388,8 @@ BEGIN
-- Gather user settings
user_settings := get_user_settings_from_vesselid_fn(data_rec.vessel_id::TEXT);
RAISE DEBUG '-> DEBUG cron_process_grafana_fn get_user_settings_from_vesselid_fn [%]', user_settings;
-- add user in keycloak
PERFORM keycloak_auth_py_fn(data_rec.vessel_id, user_settings, app_settings);
-- Send notification
PERFORM send_notification_fn('grafana'::TEXT, user_settings::JSONB);
-- update process_queue entry as processed

View File

@@ -135,9 +135,9 @@ INSERT INTO public.email_templates VALUES
E'We removed your account. Check your email!\n'),
('grafana',
'PostgSail Grafana integration',
E'Hello __RECIPIENT__,\nCongratulations! You have just unlocked Grafana\nSee more details at https://app.opneplotter.cloud\nHappy sailing!\nFrancois',
E'Hello __RECIPIENT__,\nCongratulations! You unlocked Grafana dashboard.\nSee more details at https://app.openplotter.cloud\nHappy sailing!\nFrancois',
'PostgSail Grafana!',
E'Congratulations!\nYou have just unlocked Grafana\nSee more details at https://app.opneplotter.cloud\n');
E'Congratulations!\nYou unlocked Grafana dashboard.\nSee more details at https://app.openplotter.cloud\n');
---------------------------------------------------------------------------
-- Queue handling

View File

@@ -828,7 +828,8 @@ BEGIN
OR name LIKE 'app.pushover%'
OR name LIKE 'app.url'
OR name LIKE 'app.telegram%'
OR name LIKE 'app.grafana_admin_uri';
OR name LIKE 'app.grafana_admin_uri'
OR name LIKE 'app.keycloak_uri';
END;
$get_app_settings$
LANGUAGE plpgsql;
@@ -1831,7 +1832,7 @@ BEGIN
--RAISE WARNING 'public.check_jwt() user_role vessel.name %', current_setting('vessel.name', false);
--RAISE WARNING 'public.check_jwt() user_role vessel.id %', current_setting('vessel.id', false);
ELSIF _role = 'api_anonymous' THEN
RAISE WARNING 'public.check_jwt() api_anonymous';
--RAISE WARNING 'public.check_jwt() api_anonymous';
-- Check if path is the a valid allow anonymous path
SELECT current_setting('request.path', true) ~ '^/(logs_view|log_view|rpc/timelapse_fn|monitoring_view|stats_logs_view|stats_moorages_view|rpc/stats_logs_fn)$' INTO _ppath;
if _ppath is True then
@@ -1936,16 +1937,16 @@ $$ language plpgsql;
CREATE OR REPLACE FUNCTION public.delete_account_fn(IN _email TEXT, IN _vessel_id TEXT) RETURNS BOOLEAN
AS $delete_account$
BEGIN
select count(*) from api.metrics m where vessel_id = _vessel_id;
--select count(*) from api.metrics m where vessel_id = _vessel_id;
delete from api.metrics m where vessel_id = _vessel_id;
select * from api.metadata m where vessel_id = _vessel_id;
delete from api.logbook l where vessel_id = _vessel_id;
--select * from api.metadata m where vessel_id = _vessel_id;
delete from api.moorages m where vessel_id = _vessel_id;
delete from api.logbook l where vessel_id = _vessel_id;
delete from api.stays s where vessel_id = _vessel_id;
delete from api.metadata m where vessel_id = _vessel_id;
select * from auth.vessels v where vessel_id = _vessel_id;
--select * from auth.vessels v where vessel_id = _vessel_id;
delete from auth.vessels v where vessel_id = _vessel_id;
select * from auth.accounts a where email = _email;
--select * from auth.accounts a where email = _email;
delete from auth.accounts a where email = _email;
RETURN True;
END

View File

@@ -381,11 +381,11 @@ AS $reverse_geoip_py$
#plpy.notice('IP [{}] [{}]'.format(_ip, r.status_code))
if r.status_code == 200:
#plpy.notice('Got [{}] [{}]'.format(r.text, r.status_code))
return r.json();
return r.json()
else:
plpy.error('Failed to get ip details')
return '{}'
$reverse_geoip_py$ LANGUAGE plpython3u;
return {}
$reverse_geoip_py$ IMMUTABLE strict TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u;
-- Description
COMMENT ON FUNCTION
public.reverse_geoip_py_fn
@@ -479,10 +479,10 @@ AS $overpass_py$
if r_dict["elements"]:
if "tags" in r_dict["elements"][0] and r_dict["elements"][0]["tags"]:
return r_dict["elements"][0]["tags"]; # return the first element
return '{}'
return {}
else:
plpy.notice('overpass-api Failed to get overpass-api details')
return '{}'
return {}
$overpass_py$ IMMUTABLE strict TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u;
-- Description
COMMENT ON FUNCTION
@@ -638,11 +638,11 @@ AS $keycloak_py$
safe_uri = host = user = pwd = None
if 'app.keycloak_uri' in app and app['app.keycloak_uri']:
safe_uri = urllib.parse.quote(app['app.keycloak_uri'], safe=':/?&=')
_ = urllib.parse.urlparse(safe_uri)
#safe_uri = urllib.parse.quote(app['app.keycloak_uri'], safe=':/?&=')
_ = urllib.parse.urlparse(app['app.keycloak_uri'])
host = _.netloc.split('@')[-1]
user = _.netloc.split('@')[0].split(':')[0]
pwd = _.netloc.split('@')[0].split(':')[1]
user = _.netloc.split(':')[0]
pwd = _.netloc.split(':')[1].split('@')[0]
else:
plpy.error('Error no keycloak_uri defined, check app settings')
return None
@@ -683,3 +683,86 @@ $keycloak_py$ strict TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u;
COMMENT ON FUNCTION
public.keycloak_py_fn
IS 'Return set oauth user attribute into keycloak using plpython3u';
DROP FUNCTION IF EXISTS keycloak_auth_py_fn;
CREATE OR REPLACE FUNCTION keycloak_auth_py_fn(IN _v_id TEXT,
IN _user JSONB, IN app JSONB) RETURNS JSONB
AS $keycloak_auth_py$
"""
Addkeycloak user
"""
import requests
import json
import urllib.parse
safe_uri = host = user = pwd = None
if 'app.keycloak_uri' in app and app['app.keycloak_uri']:
#safe_uri = urllib.parse.quote(app['app.keycloak_uri'], safe=':/?&=')
_ = urllib.parse.urlparse(app['app.keycloak_uri'])
host = _.netloc.split('@')[-1]
user = _.netloc.split(':')[0]
pwd = _.netloc.split(':')[1].split('@')[0]
else:
plpy.error('Error no keycloak_uri defined, check app settings')
return none
if not host or not user or not pwd:
plpy.error('Error parsing keycloak_uri, check app settings')
return None
if not 'email' in _user and _user['email']:
plpy.error('Error parsing user email, check user settings')
return none
if not _v_id:
plpy.error('Error parsing vessel_id')
return none
_headers = {'User-Agent': 'PostgSail', 'From': 'xbgmsharp@gmail.com'}
_payload = {'client_id':'admin-cli','grant_type':'password','username':user,'password':pwd}
url = f'{_.scheme}://{host}/realms/master/protocol/openid-connect/token'.format(_.scheme, host)
r = requests.post(url, headers=_headers, data=_payload, timeout=(5, 60))
#print(r.text)
#plpy.notice(url)
if r.status_code == 200 and 'access_token' in r.json():
response = r.json()
plpy.notice(response)
_headers['Authorization'] = 'Bearer '+ response['access_token']
_headers['Content-Type'] = 'application/json'
url = f'{_.scheme}://{host}/admin/realms/postgsail/users'.format(_.scheme, host)
_payload = {
"enabled": "true",
"email": _user['email'],
"firstName": _user['recipient'],
"attributes": {"vessel_id": _v_id},
"emailVerified": True,
"requiredActions":["UPDATE_PROFILE", "UPDATE_PASSWORD"]
}
plpy.notice(_payload)
data = json.dumps(_payload)
r = requests.post(url, headers=_headers, data=data, timeout=(5, 60))
if r.status_code != 201:
#print("Error creating user: {status}".format(status=r.status_code))
plpy.error(f'Error creating user: {user} {status}'.format(user=_payload['email'], status=r.status_code))
return None
else:
#print("Created user : {u}]".format(u=_payload['email']))
plpy.notice('Created user : {u} {t}, {l}'.format(u=_payload['email'], t=r.text, l=r.headers['location']))
user_url = "{user_url}/execute-actions-email".format(user_url=r.headers['location'])
_payload = ["UPDATE_PASSWORD"]
plpy.notice(_payload)
data = json.dumps(_payload)
r = requests.put(user_url, headers=_headers, data=data, timeout=(5, 60))
if r.status_code != 204:
plpy.error('Error execute-actions-email: {u} {s}'.format(u=_user['email'], s=r.status_code))
else:
plpy.notice('execute-actions-email: {u} {s}'.format(u=_user['email'], s=r.status_code))
return None
else:
plpy.error(f'Error getting admin access_token: {status}'.format(status=r.status_code))
return None
$keycloak_auth_py$ strict TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u;
-- Description
COMMENT ON FUNCTION
public.keycloak_auth_py_fn
IS 'Return set oauth user attribute into keycloak using plpython3u';

View File

@@ -248,7 +248,7 @@ BEGIN
'ship_type', (SELECT ais.description FROM aistypes ais, tbl t WHERE t.ship_type = ais.id),
'country', (SELECT mid.country FROM mid, tbl t WHERE LEFT(cast(t.mmsi as text), 3)::NUMERIC = mid.id),
'alpha_2', (SELECT o.alpha_2 FROM mid m, iso3166 o, tbl t WHERE LEFT(cast(t.mmsi as text), 3)::NUMERIC = m.id AND m.country_id = o.id),
'length', t.ship_type,
'length', t.length,
'beam', t.beam,
'height', t.height,
'plugin_version', t.plugin_version,

View File

@@ -1 +1 @@
0.6.0
0.6.1

View File

@@ -645,10 +645,10 @@ overpass_py_fn | {"name": "Port de la Ginesta", "type": "multipolygon", "leisure
overpass_py_fn | {"name": "Norra hamnen", "leisure": "marina"}
-[ RECORD 1 ]----------------------------------------------------------------------------------------------------------------------------------------------
versions_fn | {"api_version" : "0.6.0", "sys_version" : "PostgreSQL 16.1", "timescaledb" : "2.13.1", "postgis" : "3.4.1", "postgrest" : "PostgREST 12.0.2"}
versions_fn | {"api_version" : "0.6.1", "sys_version" : "PostgreSQL 16.1", "timescaledb" : "2.13.1", "postgis" : "3.4.1", "postgrest" : "PostgREST 12.0.2"}
-[ RECORD 1 ]-----------------
api_version | 0.6.0
api_version | 0.6.1
sys_version | PostgreSQL 16.1
timescaledb | 2.13.1
postgis | 3.4.1