mirror of
https://github.com/xbgmsharp/postgsail.git
synced 2025-09-17 03:07:47 +00:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
51b6e8fa7c | ||
![]() |
89af44efcc | ||
![]() |
a64ef5850d | ||
![]() |
da100ddd18 | ||
![]() |
92ce0503dd | ||
![]() |
61d40fd7b6 | ||
![]() |
c318f2d338 | ||
![]() |
c7c14fa5a1 | ||
![]() |
4fc68ae805 | ||
![]() |
3eb67abedb | ||
![]() |
894dbf0667 | ||
![]() |
f526b99853 | ||
![]() |
a670038f28 | ||
![]() |
2599f40f7b | ||
![]() |
4d833999e8 | ||
![]() |
b4dc93ba0e | ||
![]() |
764a6d6457 | ||
![]() |
2e9ede6da2 | ||
![]() |
cc67a3b37d | ||
![]() |
64ecbfc698 | ||
![]() |
b19eeed59a | ||
![]() |
8f5cd4237d | ||
![]() |
7b3a1451bb | ||
![]() |
a2cdd8ddfe | ||
![]() |
7a04026e67 | ||
![]() |
fab496ea3d | ||
![]() |
4f31831c94 | ||
![]() |
300e4bee48 | ||
![]() |
99e258c974 | ||
![]() |
970c85c11e | ||
![]() |
bbf4426f55 | ||
![]() |
a8620f4b4c | ||
![]() |
15accaa4cb | ||
![]() |
8d382b48ac | ||
![]() |
2983f149ad |
@@ -12,8 +12,9 @@ PGSAIL_EMAIL_SERVER=localhost
|
||||
#PGSAIL_EMAIL_PASS= Comment if not use
|
||||
#PGSAIL_PUSHOVER_APP_TOKEN= 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_API_URL=http://localhost
|
||||
# POSTGREST ENV Settings
|
||||
PGRST_DB_URI=postgres://authenticator:${PGSAIL_AUTHENTICATOR_PASSWORD}@127.0.0.1:5432/signalk
|
||||
PGRST_JWT_SECRET=_at_least_32__char__long__random
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 104 KiB |
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 30 KiB |
@@ -13,7 +13,7 @@ There is 3 main schemas:
|
||||
- ...
|
||||
- functions
|
||||
- ...
|
||||

|
||||

|
||||
|
||||
- Auth Schema ERD
|
||||
- tables
|
||||
@@ -22,7 +22,7 @@ There is 3 main schemas:
|
||||
- ...
|
||||
- functions
|
||||
- ...
|
||||

|
||||

|
||||
|
||||
- Public Schema ERD
|
||||
- tables
|
||||
@@ -31,5 +31,5 @@ There is 3 main schemas:
|
||||
- ...
|
||||
- functions
|
||||
- ...
|
||||

|
||||

|
||||
|
||||
|
BIN
ERD/signalk - api.png
Normal file
BIN
ERD/signalk - api.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 222 KiB |
BIN
ERD/signalk - auth.png
Normal file
BIN
ERD/signalk - auth.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
ERD/signalk - public.png
Normal file
BIN
ERD/signalk - public.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
11
Why.md
Normal file
11
Why.md
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#### Why not InfluxDB vs TimescaleDB
|
||||
I had an InfluxDBv1 on my RPI that kill the sdcard. I had an InfluxDBv2, but no more ARM support and had to learn flux. Also could not find a good way to store data when offline. How do you export your data from a InfluxDBv2? Still looking for a solution.
|
||||
|
||||
With TimescaleDB, we all ready know SQL and there is a lot of tools and librairies that work with Postgres.
|
||||
However, InfluxDB does simplify things like schema and provide an http endpoint.
|
||||
With TimescaleDB, you are using a standard SQL table schema to store data from Signalk.
|
||||
|
||||
#### Why not MQTT vs HTTP
|
||||
Having MQTT, makes your application micro service approach. however you multiple the compoments and dependecy. HTTP seem a more realibale solution specaily for offline support as MQTT library have a buffer limitation.
|
||||
Using PostgREST is an alternative to manual CRUD programming. Custom API servers suffer problems. Writing business logic often duplicates, ignores or hobbles database structure. Object-relational mapping is a leaky abstraction leading to slow imperative code. The PostgREST philosophy establishes a single declarative source of truth: the data itself.
|
@@ -79,5 +79,50 @@ services:
|
||||
# retries: 5
|
||||
# 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/vuestic-postgsail:dev
|
||||
build:
|
||||
context: https://github.com/xbgmsharp/vuestic-postgsail.git#live
|
||||
dockerfile: Dockerfile_dev
|
||||
container_name: web_dev
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /etc/resolv.conf:/etc/resolv.conf:ro
|
||||
ports:
|
||||
- "3006:8080"
|
||||
network_mode: "host"
|
||||
env_file: .env
|
||||
environment:
|
||||
- VITE_PGSAIL_URL=${PGSAIL_API_URL}
|
||||
- VUE_APP_INCLUDE_DEMOS=false
|
||||
- VITE_APP_BUILD_VERSION=true
|
||||
- VITE_APP_TITLE=PostgSail Dev
|
||||
depends_on:
|
||||
- db
|
||||
- api
|
||||
logging:
|
||||
options:
|
||||
max-size: 10m
|
||||
|
||||
volumes:
|
||||
data: {}
|
||||
|
1455
grafana/dashboards/Electrical.json
Normal file
1455
grafana/dashboards/Electrical.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -133,7 +133,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT * from api.logs_view",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT * from api.logs_view",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -262,7 +262,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT * from api.stays_view",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT * from api.stays_view",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -391,7 +391,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nselect * from api.moorages_view",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nselect * from api.moorages_view",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -442,7 +442,7 @@
|
||||
"type": "postgres",
|
||||
"uid": "PCC52D03280B7034C"
|
||||
},
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"description": "Vessel Name",
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
@@ -450,7 +450,7 @@
|
||||
"multi": false,
|
||||
"name": "boat",
|
||||
"options": [],
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
|
@@ -104,7 +104,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'electrical.batteries.AUX2.voltage' AS numeric) AS AUX2Voltage\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'electrical.batteries.AUX2.voltage' AS numeric) AS AUX2Voltage\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -210,7 +210,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS OutsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS OutsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -370,7 +370,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'electrical.batteries.AUX2.voltage' AS numeric) AS AUX2,\n\tcast(metrics-> 'electrical.batteries.House.voltage' AS numeric) AS House,\n\tcast(metrics-> 'environment.rpi.pijuice.gpioVoltage' AS numeric) AS gpioVoltage,\n\tcast(metrics-> 'electrical.batteries.Seatalk.voltage' AS numeric) AS SeatalkVoltage,\n\tcast(metrics-> 'electrical.batteries.Starter.voltage' AS numeric) AS StarterVoltage,\n\tcast(metrics-> 'environment.rpi.pijuice.batteryVoltage' AS numeric) AS RPIBatteryVoltage,\n\tcast(metrics-> 'electrical.batteries.victronDevice.voltage' AS numeric) AS victronDeviceVoltage\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n\tAND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'electrical.batteries.AUX2.voltage' AS numeric) AS AUX2,\n\tcast(metrics-> 'electrical.batteries.House.voltage' AS numeric) AS House,\n\tcast(metrics-> 'environment.rpi.pijuice.gpioVoltage' AS numeric) AS gpioVoltage,\n\tcast(metrics-> 'electrical.batteries.Seatalk.voltage' AS numeric) AS SeatalkVoltage,\n\tcast(metrics-> 'electrical.batteries.Starter.voltage' AS numeric) AS StarterVoltage,\n\tcast(metrics-> 'environment.rpi.pijuice.batteryVoltage' AS numeric) AS RPIBatteryVoltage,\n\tcast(metrics-> 'electrical.batteries.victronDevice.voltage' AS numeric) AS victronDeviceVoltage\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n\tAND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -505,7 +505,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature,\n\tcast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature,\n\tcast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature,\n\tcast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature,\n\tcast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -638,7 +638,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nwith config as (select set_config('vessel.id', '${boat}', false) ) select * from api.monitoring_view",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nwith config as (select set_config('vessel.id', '${boat}', false) ) select * from api.monitoring_view",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -695,7 +695,7 @@
|
||||
"type": "postgres",
|
||||
"uid": "PCC52D03280B7034C"
|
||||
},
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"description": "Vessel name",
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
@@ -703,7 +703,7 @@
|
||||
"multi": false,
|
||||
"name": "boat",
|
||||
"options": [],
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
|
1341
grafana/dashboards/RPI.json
Normal file
1341
grafana/dashboards/RPI.json
Normal file
File diff suppressed because it is too large
Load Diff
1987
grafana/dashboards/Solar.json
Normal file
1987
grafana/dashboards/Solar.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -118,7 +118,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n time AS \"time\",\n cast(windspeedapparent AS numeric) * 1.9438444924406 AS windSpeed\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n and client_id = '${boat}'\nORDER BY 1\n",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(windspeedapparent AS numeric) * 1.9438444924406 AS windSpeed\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n and vessel_id = '${boat}'\nORDER BY 1\n",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -236,7 +236,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT cast(anglespeedapparent AS numeric) AS windAngleTrue from api.metrics WHERE client_id = '${boat}' ORDER BY time DESC LIMIT 1;",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT cast(anglespeedapparent AS numeric) AS windAngleTrue from api.metrics WHERE vessel_id = '${boat}' ORDER BY time DESC LIMIT 1;",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -363,7 +363,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -487,7 +487,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -603,7 +603,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.pressure' AS numeric) * 0.00029530 AS outsidePressure\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1\n",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.pressure' AS numeric) * 0.00029530 AS outsidePressure\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1\n",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -726,7 +726,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -852,7 +852,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.humidity' AS numeric) * 100 AS insideHumidity\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.humidity' AS numeric) * 100 AS insideHumidity\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -976,7 +976,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.engine.temperature' AS numeric) - 273.15 AS insideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.engine.temperature' AS numeric) - 273.15 AS insideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1134,7 +1134,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT time AS \"time\", cast(windspeedapparent AS numeric) * 1.9438444924406 AS windSpeed\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT time AS \"time\", cast(windspeedapparent AS numeric) * 1.9438444924406 AS windSpeed\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1331,7 +1331,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature,\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature,\n cast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature,\n cast(metrics-> 'environment.inside.fridge.temperature' AS numeric) - 273.15 AS fridgeTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.water.temperature' AS numeric) - 273.15 AS waterTemperature,\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature,\n cast(metrics-> 'environment.inside.temperature' AS numeric) - 273.15 AS insideTemperature,\n cast(metrics-> 'environment.inside.fridge.temperature' AS numeric) - 273.15 AS fridgeTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1439,7 +1439,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.temperature' AS numeric) - 273.15 AS outsideTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1576,7 +1576,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.pressure' AS numeric) * 0.00029530 AS outsideTemperature,\n cast(metrics-> 'environment.inside.pressure' AS numeric) * 0.00029530 AS insideTemperature,\n cast(metrics-> 'environment.inside.fridge.pressure' AS numeric) * 0.00029530 AS fridgeTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n cast(metrics-> 'environment.outside.pressure' AS numeric) * 0.00029530 AS outsideTemperature,\n cast(metrics-> 'environment.inside.pressure' AS numeric) * 0.00029530 AS insideTemperature,\n cast(metrics-> 'environment.inside.fridge.pressure' AS numeric) * 0.00029530 AS fridgeTemperature\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1742,7 +1742,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n anglespeedapparent\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n anglespeedapparent\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1878,7 +1878,7 @@
|
||||
"group": [],
|
||||
"metricColumn": "none",
|
||||
"rawQuery": true,
|
||||
"rawSql": "SET vessel.client_id = '${__user.login}';\nSELECT\n time AS \"time\",\n windSpeedApparent\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND client_id = '${boat}'\nORDER BY 1",
|
||||
"rawSql": "SET vessel.id = '${__user.login}';\nSELECT\n time AS \"time\",\n windSpeedApparent\nFROM api.metrics\nWHERE\n $__timeFilter(time)\n AND vessel_id = '${boat}'\nORDER BY 1",
|
||||
"refId": "A",
|
||||
"select": [
|
||||
[
|
||||
@@ -1947,7 +1947,7 @@
|
||||
"type": "postgres",
|
||||
"uid": "PCC52D03280B7034C"
|
||||
},
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"definition": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"description": "Vessel Name",
|
||||
"hide": 0,
|
||||
"includeAll": false,
|
||||
@@ -1955,7 +1955,7 @@
|
||||
"multi": false,
|
||||
"name": "boat",
|
||||
"options": [],
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.client_id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.client_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"query": "SET \"user.email\" = '${__user.email}';\nSET vessel.id = '${__user.login}';\nSELECT\n v.name AS __text,\n m.vessel_id AS __value\n FROM auth.vessels v\n JOIN api.metadata m ON v.owner_email = '${__user.email}' and m.vessel_id = v.vessel_id;",
|
||||
"refresh": 1,
|
||||
"regex": "",
|
||||
"skipUrlSync": false,
|
||||
|
@@ -82,18 +82,19 @@ UPDATE pg_language SET lanpltrusted = true WHERE lanname = 'plpython3u';
|
||||
-- Metadata from signalk
|
||||
CREATE TABLE IF NOT EXISTS api.metadata(
|
||||
id SERIAL PRIMARY KEY,
|
||||
name VARCHAR(150) NULL,
|
||||
name TEXT NULL,
|
||||
mmsi NUMERIC NULL,
|
||||
client_id VARCHAR(255) UNIQUE NOT NULL,
|
||||
client_id TEXT NULL,
|
||||
-- vessel_id link auth.vessels with api.metadata
|
||||
vessel_id TEXT NOT NULL UNIQUE,
|
||||
length DOUBLE PRECISION NULL,
|
||||
beam DOUBLE PRECISION NULL,
|
||||
height DOUBLE PRECISION NULL,
|
||||
ship_type NUMERIC NULL,
|
||||
plugin_version VARCHAR(10) NOT NULL,
|
||||
signalk_version VARCHAR(10) NOT NULL,
|
||||
plugin_version TEXT NOT NULL,
|
||||
signalk_version TEXT NOT NULL,
|
||||
time TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- should be rename to last_update !?
|
||||
active BOOLEAN DEFAULT True, -- trigger monitor online/offline
|
||||
-- vessel_id link auth.vessels with api.metadata
|
||||
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW()
|
||||
);
|
||||
@@ -103,8 +104,8 @@ COMMENT ON TABLE
|
||||
IS 'Stores metadata from vessel';
|
||||
COMMENT ON COLUMN api.metadata.active IS 'trigger monitor online/offline';
|
||||
-- Index
|
||||
CREATE INDEX metadata_client_id_idx ON api.metadata (client_id);
|
||||
CREATE INDEX metadata_mmsi_idx ON api.metadata (mmsi);
|
||||
CREATE INDEX metadata_vessel_id_idx ON api.metadata (vessel_id);
|
||||
--CREATE INDEX metadata_mmsi_idx ON api.metadata (mmsi);
|
||||
CREATE INDEX metadata_name_idx ON api.metadata (name);
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
@@ -114,7 +115,9 @@ CREATE TYPE status AS ENUM ('sailing', 'motoring', 'moored', 'anchored');
|
||||
-- Table api.metrics
|
||||
CREATE TABLE IF NOT EXISTS api.metrics (
|
||||
time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
--client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
client_id TEXT NULL,
|
||||
vessel_id TEXT NOT NULL REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT,
|
||||
latitude DOUBLE PRECISION NULL,
|
||||
longitude DOUBLE PRECISION NULL,
|
||||
speedOverGround DOUBLE PRECISION NULL,
|
||||
@@ -123,7 +126,7 @@ CREATE TABLE IF NOT EXISTS api.metrics (
|
||||
angleSpeedApparent DOUBLE PRECISION NULL,
|
||||
status status NULL,
|
||||
metrics jsonb NULL,
|
||||
CONSTRAINT valid_client_id CHECK (length(client_id) > 10),
|
||||
--CONSTRAINT valid_client_id CHECK (length(client_id) > 10),
|
||||
CONSTRAINT valid_latitude CHECK (latitude >= -90 and latitude <= 90),
|
||||
CONSTRAINT valid_longitude CHECK (longitude >= -180 and longitude <= 180)
|
||||
);
|
||||
@@ -135,21 +138,22 @@ COMMENT ON COLUMN api.metrics.latitude IS 'With CONSTRAINT but allow NULL value
|
||||
COMMENT ON COLUMN api.metrics.longitude IS 'With CONSTRAINT but allow NULL value to be ignored silently by trigger';
|
||||
|
||||
-- Index
|
||||
CREATE INDEX ON api.metrics (client_id, time DESC);
|
||||
CREATE INDEX ON api.metrics (vessel_id, time DESC);
|
||||
CREATE INDEX ON api.metrics (status, time DESC);
|
||||
-- json index??
|
||||
CREATE INDEX ON api.metrics using GIN (metrics);
|
||||
-- timescaledb hypertable
|
||||
--SELECT create_hypertable('api.metrics', 'time');
|
||||
SELECT create_hypertable('api.metrics', 'time', chunk_time_interval => INTERVAL '7 day');
|
||||
-- timescaledb hypertable with space partitions
|
||||
SELECT create_hypertable('api.metrics', 'time', 'client_id',
|
||||
number_partitions => 2,
|
||||
chunk_time_interval => INTERVAL '7 day',
|
||||
if_not_exists => true);
|
||||
-- ERROR: new row for relation "_hyper_1_2_chunk" violates check constraint "constraint_4"
|
||||
-- ((_timescaledb_internal.get_partition_hash(vessel_id) < 1073741823))
|
||||
--SELECT create_hypertable('api.metrics', 'time', 'vessel_id',
|
||||
-- number_partitions => 2,
|
||||
-- chunk_time_interval => INTERVAL '7 day',
|
||||
-- if_not_exists => true);
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Logbook
|
||||
-- todo add clientid ref
|
||||
-- todo add cosumption fuel?
|
||||
-- todo add engine hour?
|
||||
-- todo add geom object http://epsg.io/4326 EPSG:4326 Unit: degres
|
||||
@@ -162,8 +166,9 @@ SELECT create_hypertable('api.metrics', 'time', 'client_id',
|
||||
-- https://www.reddit.com/r/PostgreSQL/comments/di5mbr/postgresql_12_foreign_keys_and_partitioned_tables/f3tsoop/
|
||||
CREATE TABLE IF NOT EXISTS api.logbook(
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
-- client_id VARCHAR(255) NOT NULL,
|
||||
--client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
--client_id VARCHAR(255) NULL,
|
||||
vessel_id TEXT NOT NULL REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT,
|
||||
active BOOLEAN DEFAULT false,
|
||||
name VARCHAR(255),
|
||||
_from VARCHAR(255),
|
||||
@@ -176,7 +181,7 @@ CREATE TABLE IF NOT EXISTS api.logbook(
|
||||
track_geom geometry(LINESTRING,4326) NULL,
|
||||
track_geog geography(LINESTRING) NULL,
|
||||
track_geojson JSON NULL,
|
||||
-- track_gpx XML NULL,
|
||||
track_gpx XML NULL,
|
||||
_from_time TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
_to_time TIMESTAMP WITHOUT TIME ZONE NULL,
|
||||
distance NUMERIC, -- meters?
|
||||
@@ -193,24 +198,23 @@ COMMENT ON TABLE
|
||||
COMMENT ON COLUMN api.logbook.distance IS 'in NM';
|
||||
|
||||
-- Index todo!
|
||||
CREATE INDEX logbook_client_id_idx ON api.logbook (client_id);
|
||||
CREATE INDEX logbook_vessel_id_idx ON api.logbook (vessel_id);
|
||||
CREATE INDEX ON api.logbook USING GIST ( track_geom );
|
||||
COMMENT ON COLUMN api.logbook.track_geom IS 'postgis geometry type EPSG:4326 Unit: degres';
|
||||
CREATE INDEX ON api.logbook USING GIST ( track_geog );
|
||||
COMMENT ON COLUMN api.logbook.track_geog IS 'postgis geography type default SRID 4326 Unit: degres';
|
||||
-- Otherwise -- ERROR: Only lon/lat coordinate systems are supported in geography.
|
||||
COMMENT ON COLUMN api.logbook.track_geojson IS 'store the geojson track metrics data, can not depend api.metrics table, should be generate from linetring to save disk space?';
|
||||
--COMMENT ON COLUMN api.logbook.track_gpx IS 'store the gpx track metrics data, can not depend api.metrics table, should be generate from linetring to save disk space?';
|
||||
COMMENT ON COLUMN api.logbook.track_gpx IS 'store the gpx track metrics data, can not depend api.metrics table, should be generate from linetring to save disk space?';
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Stays
|
||||
-- todo add clientid ref
|
||||
-- todo add FOREIGN KEY?
|
||||
-- virtual logbook by boat?
|
||||
CREATE TABLE IF NOT EXISTS api.stays(
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
-- client_id VARCHAR(255) NOT NULL,
|
||||
--client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
--client_id VARCHAR(255) NULL,
|
||||
vessel_id TEXT NOT NULL REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT,
|
||||
active BOOLEAN DEFAULT false,
|
||||
name VARCHAR(255),
|
||||
latitude DOUBLE PRECISION NULL,
|
||||
@@ -228,21 +232,21 @@ COMMENT ON TABLE
|
||||
IS 'Stores generated stays';
|
||||
|
||||
-- Index
|
||||
CREATE INDEX stays_client_id_idx ON api.stays (client_id);
|
||||
CREATE INDEX stays_vessel_id_idx ON api.stays (vessel_id);
|
||||
CREATE INDEX ON api.stays USING GIST ( geog );
|
||||
COMMENT ON COLUMN api.stays.geog IS 'postgis geography type default SRID 4326 Unit: degres';
|
||||
-- With other SRID ERROR: Only lon/lat coordinate systems are supported in geography.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Moorages
|
||||
-- todo add clientid ref
|
||||
-- virtual logbook by boat?
|
||||
CREATE TABLE IF NOT EXISTS api.moorages(
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
-- client_id VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255),
|
||||
country VARCHAR(255), -- todo need to update reverse_geocode_py_fn
|
||||
--client_id VARCHAR(255) NOT NULL REFERENCES api.metadata(client_id) ON DELETE RESTRICT,
|
||||
--client_id VARCHAR(255) NULL,
|
||||
vessel_id TEXT NOT NULL REFERENCES api.metadata(vessel_id) ON DELETE RESTRICT,
|
||||
name TEXT,
|
||||
country TEXT, -- todo need to update reverse_geocode_py_fn
|
||||
stay_id INT NOT NULL, -- needed?
|
||||
stay_code INT DEFAULT 1, -- needed? REFERENCES api.stays_at(stay_code)
|
||||
stay_duration INTERVAL NULL,
|
||||
@@ -259,7 +263,7 @@ COMMENT ON TABLE
|
||||
IS 'Stores generated moorages';
|
||||
|
||||
-- Index
|
||||
CREATE INDEX moorages_client_id_idx ON api.moorages (client_id);
|
||||
CREATE INDEX moorages_vessel_id_idx ON api.moorages (vessel_id);
|
||||
CREATE INDEX ON api.moorages USING GIST ( geog );
|
||||
COMMENT ON COLUMN api.moorages.geog IS 'postgis geography type default SRID 4326 Unit: degres';
|
||||
-- With other SRID ERROR: Only lon/lat coordinate systems are supported in geography.
|
||||
@@ -290,20 +294,21 @@ CREATE FUNCTION metadata_upsert_trigger_fn() RETURNS trigger AS $metadata_upsert
|
||||
metadata_active boolean;
|
||||
BEGIN
|
||||
-- Set client_id to new value to allow RLS
|
||||
PERFORM set_config('vessel.client_id', NEW.client_id, false);
|
||||
--PERFORM set_config('vessel.client_id', NEW.client_id, false);
|
||||
-- UPSERT - Insert vs Update for Metadata
|
||||
RAISE NOTICE 'metadata_upsert_trigger_fn';
|
||||
--PERFORM set_config('vessel.id', NEW.vessel_id, true);
|
||||
RAISE WARNING 'metadata_upsert_trigger_fn [%] [%]', current_setting('vessel.id', true), NEW;
|
||||
SELECT m.id,m.active INTO metadata_id, metadata_active
|
||||
FROM api.metadata m
|
||||
WHERE (m.vessel_id IS NOT NULL AND m.vessel_id = current_setting('vessel.id', true))
|
||||
OR (m.client_id IS NOT NULL AND m.client_id = NEW.client_id);
|
||||
WHERE m.vessel_id IS NOT NULL AND m.vessel_id = current_setting('vessel.id', true);
|
||||
RAISE NOTICE 'metadata_id %', metadata_id;
|
||||
IF metadata_id IS NOT NULL THEN
|
||||
-- send notifitacion if boat is back online
|
||||
IF metadata_active is False THEN
|
||||
-- Add monitor online entry to process queue for later notification
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('monitoring_online', metadata_id, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('monitoring_online', metadata_id, now(), current_setting('vessel.id', true));
|
||||
END IF;
|
||||
-- Update vessel metadata
|
||||
UPDATE api.metadata
|
||||
@@ -350,9 +355,9 @@ DROP FUNCTION IF EXISTS metadata_notification_trigger_fn;
|
||||
CREATE FUNCTION metadata_notification_trigger_fn() RETURNS trigger AS $metadata_notification$
|
||||
DECLARE
|
||||
BEGIN
|
||||
RAISE NOTICE 'metadata_notification_trigger_fn';
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('monitoring_online', NEW.id, now());
|
||||
RAISE NOTICE 'metadata_notification_trigger_fn [%]', NEW;
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('monitoring_online', NEW.id, now(), NEW.vessel_id);
|
||||
RETURN NULL;
|
||||
END;
|
||||
$metadata_notification$ LANGUAGE plpgsql;
|
||||
@@ -395,55 +400,57 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
logbook_id integer;
|
||||
stay_id integer;
|
||||
valid_status BOOLEAN;
|
||||
_vessel_id TEXT;
|
||||
BEGIN
|
||||
-- Set client_id to new value to allow RLS
|
||||
PERFORM set_config('vessel.client_id', NEW.client_id, false);
|
||||
--PERFORM set_config('vessel.client_id', NEW.client_id, false);
|
||||
NEW.vessel_id = current_setting('vessel.id', true);
|
||||
--RAISE NOTICE 'metrics_trigger_fn client_id [%]', NEW.client_id;
|
||||
-- Boat metadata are check using api.metrics REFERENCES to api.metadata
|
||||
-- Fetch the latest entry to compare status against the new status to be insert
|
||||
SELECT coalesce(m.status, 'moored'), m.time INTO previous_status, previous_time
|
||||
FROM api.metrics m
|
||||
WHERE m.client_id IS NOT NULL
|
||||
AND m.client_id = NEW.client_id
|
||||
WHERE m.vessel_id IS NOT NULL
|
||||
AND m.vessel_id = current_setting('vessel.id', true)
|
||||
ORDER BY m.time DESC LIMIT 1;
|
||||
--RAISE NOTICE 'Metrics Status, New:[%] Previous:[%]', NEW.status, previous_status;
|
||||
IF previous_time = NEW.time THEN
|
||||
-- Ignore entry if same time
|
||||
RAISE WARNING 'Metrics Ignoring metric, duplicate time [%] = [%]', previous_time, NEW.time;
|
||||
RAISE WARNING 'Metrics Ignoring metric, vessel_id [%], duplicate time [%] = [%]', NEW.vessel_id, previous_time, NEW.time;
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
IF previous_time > NEW.time THEN
|
||||
-- Ignore entry if new time is later than previous time
|
||||
RAISE WARNING 'Metrics Ignoring metric, new time is older [%] > [%]', previous_time, NEW.time;
|
||||
RAISE WARNING 'Metrics Ignoring metric, vessel_id [%], new time is older [%] > [%]', NEW.vessel_id, previous_time, NEW.time;
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
-- Check if latitude or longitude are null
|
||||
IF NEW.latitude IS NULL OR NEW.longitude IS NULL THEN
|
||||
-- Ignore entry if null latitude,longitude
|
||||
RAISE WARNING 'Metrics Ignoring metric, null latitude,longitude [%] [%]', NEW.latitude, NEW.longitude;
|
||||
RAISE WARNING 'Metrics Ignoring metric, vessel_id [%], null latitude,longitude [%] [%]', NEW.vessel_id, NEW.latitude, NEW.longitude;
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
-- Check if status is null
|
||||
IF NEW.status IS NULL THEN
|
||||
RAISE WARNING 'Metrics Unknow NEW.status from vessel [%], set to default moored', NEW.status;
|
||||
RAISE WARNING 'Metrics Unknow NEW.status, vessel_id [%], null status, set to default moored from [%]', NEW.vessel_id, NEW.status;
|
||||
NEW.status := 'moored';
|
||||
END IF;
|
||||
IF previous_status IS NULL THEN
|
||||
IF NEW.status = 'anchored' THEN
|
||||
RAISE WARNING 'Metrics Unknow previous_status from vessel [%], set to default current status [%]', previous_status, NEW.status;
|
||||
RAISE WARNING 'Metrics Unknow previous_status from vessel_id [%], [%] set to default current status [%]', NEW.vessel_id, previous_status, NEW.status;
|
||||
previous_status := NEW.status;
|
||||
ELSE
|
||||
RAISE WARNING 'Metrics Unknow previous_status from vessel [%], set to default status moored vs [%]', previous_status, NEW.status;
|
||||
RAISE WARNING 'Metrics Unknow previous_status from vessel_id [%], [%] set to default status moored vs [%]', NEW.vessel_id, previous_status, NEW.status;
|
||||
previous_status := 'moored';
|
||||
END IF;
|
||||
-- Add new stay as no previous entry exist
|
||||
INSERT INTO api.stays
|
||||
(client_id, active, arrived, latitude, longitude, stay_code)
|
||||
VALUES (NEW.client_id, true, NEW.time, NEW.latitude, NEW.longitude, 1)
|
||||
(vessel_id, active, arrived, latitude, longitude, stay_code)
|
||||
VALUES (current_setting('vessel.id', true), true, NEW.time, NEW.latitude, NEW.longitude, 1)
|
||||
RETURNING id INTO stay_id;
|
||||
-- Add stay entry to process queue for further processing
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('new_stay', stay_id, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('new_stay', stay_id, now(), current_setting('vessel.id', true));
|
||||
RAISE WARNING 'Metrics Insert first stay as no previous metrics exist, stay_id %', stay_id;
|
||||
END IF;
|
||||
-- Check if status is valid enum
|
||||
@@ -461,11 +468,11 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
OR (NEW.status::TEXT = 'motoring' AND previous_status::TEXT <> 'sailing') ) THEN
|
||||
RAISE WARNING 'Metrics Update status, try new logbook, New:[%] Previous:[%]', NEW.status, previous_status;
|
||||
-- Start new log
|
||||
logbook_id := public.trip_in_progress_fn(NEW.client_id::TEXT);
|
||||
logbook_id := public.trip_in_progress_fn(current_setting('vessel.id', true)::TEXT);
|
||||
IF logbook_id IS NULL THEN
|
||||
INSERT INTO api.logbook
|
||||
(client_id, active, _from_time, _from_lat, _from_lng)
|
||||
VALUES (NEW.client_id, true, NEW.time, NEW.latitude, NEW.longitude)
|
||||
(vessel_id, active, _from_time, _from_lat, _from_lng)
|
||||
VALUES (current_setting('vessel.id', true), true, NEW.time, NEW.latitude, NEW.longitude)
|
||||
RETURNING id INTO logbook_id;
|
||||
RAISE WARNING 'Metrics Insert new logbook, logbook_id %', logbook_id;
|
||||
ELSE
|
||||
@@ -480,7 +487,7 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
END IF;
|
||||
|
||||
-- End current stay
|
||||
stay_id := public.stay_in_progress_fn(NEW.client_id::TEXT);
|
||||
stay_id := public.stay_in_progress_fn(current_setting('vessel.id', true)::TEXT);
|
||||
IF stay_id IS NOT NULL THEN
|
||||
UPDATE api.stays
|
||||
SET
|
||||
@@ -489,8 +496,8 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
WHERE id = stay_id;
|
||||
RAISE WARNING 'Metrics Updating Stay end current stay_id [%] [%] [%]', stay_id, NEW.status, NEW.time;
|
||||
-- Add moorage entry to process queue for further processing
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('new_moorage', stay_id, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('new_moorage', stay_id, now(), current_setting('vessel.id', true));
|
||||
ELSE
|
||||
RAISE WARNING 'Metrics Invalid stay_id [%] [%]', stay_id, NEW.time;
|
||||
END IF;
|
||||
@@ -501,7 +508,7 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
OR (NEW.status::TEXT = 'anchored' AND previous_status::TEXT <> 'moored') ) THEN
|
||||
-- Start new stays
|
||||
RAISE WARNING 'Metrics Update status, try new stay, New:[%] Previous:[%]', NEW.status, previous_status;
|
||||
stay_id := public.stay_in_progress_fn(NEW.client_id::TEXT);
|
||||
stay_id := public.stay_in_progress_fn(current_setting('vessel.id', true)::TEXT);
|
||||
IF stay_id IS NULL THEN
|
||||
RAISE WARNING 'Metrics Inserting new stay [%]', NEW.status;
|
||||
-- If metric status is anchored set stay_code accordingly
|
||||
@@ -511,12 +518,12 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
END IF;
|
||||
-- Add new stay
|
||||
INSERT INTO api.stays
|
||||
(client_id, active, arrived, latitude, longitude, stay_code)
|
||||
VALUES (NEW.client_id, true, NEW.time, NEW.latitude, NEW.longitude, stay_code)
|
||||
(vessel_id, active, arrived, latitude, longitude, stay_code)
|
||||
VALUES (current_setting('vessel.id', true), true, NEW.time, NEW.latitude, NEW.longitude, stay_code)
|
||||
RETURNING id INTO stay_id;
|
||||
-- Add stay entry to process queue for further processing
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('new_stay', stay_id, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('new_stay', stay_id, now(), current_setting('vessel.id', true));
|
||||
ELSE
|
||||
RAISE WARNING 'Metrics Invalid stay_id [%] [%]', stay_id, NEW.time;
|
||||
UPDATE api.stays
|
||||
@@ -527,8 +534,8 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
END IF;
|
||||
|
||||
-- End current log/trip
|
||||
-- Fetch logbook_id by client_id
|
||||
logbook_id := public.trip_in_progress_fn(NEW.client_id::TEXT);
|
||||
-- Fetch logbook_id by vessel_id
|
||||
logbook_id := public.trip_in_progress_fn(current_setting('vessel.id', true)::TEXT);
|
||||
IF logbook_id IS NOT NULL THEN
|
||||
-- todo check on time start vs end
|
||||
RAISE WARNING 'Metrics Updating logbook status [%] [%] [%]', logbook_id, NEW.status, NEW.time;
|
||||
@@ -540,8 +547,8 @@ CREATE FUNCTION metrics_trigger_fn() RETURNS trigger AS $metrics$
|
||||
_to_lng = NEW.longitude
|
||||
WHERE id = logbook_id;
|
||||
-- Add logbook entry to process queue for later processing
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUEs ('new_logbook', logbook_id, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUEs ('new_logbook', logbook_id, now(), current_setting('vessel.id', true));
|
||||
ELSE
|
||||
RAISE WARNING 'Metrics Invalid logbook_id [%] [%]', logbook_id, NEW.time;
|
||||
END IF;
|
||||
@@ -628,7 +635,7 @@ CREATE FUNCTION api.export_logbook_geojson_fn(IN _id integer, OUT geojson JSON)
|
||||
SELECT * INTO logbook_rec
|
||||
FROM api.logbook WHERE id = _id;
|
||||
-- Ensure the query is successful
|
||||
IF logbook_rec.client_id IS NULL THEN
|
||||
IF logbook_rec.vessel_id IS NULL THEN
|
||||
RAISE WARNING '-> export_logbook_geojson_fn invalid logbook %', _id;
|
||||
RETURN;
|
||||
END IF;
|
||||
@@ -660,7 +667,7 @@ AS $export_logbook_gpx$
|
||||
api.logbook l
|
||||
WHERE l.id = _id;
|
||||
-- Ensure the query is successful
|
||||
IF log_rec.client_id IS NULL THEN
|
||||
IF log_rec.vessel_id IS NULL THEN
|
||||
RAISE WARNING '-> export_logbook_gpx_fn invalid logbook %', _id;
|
||||
RETURN '';
|
||||
END IF;
|
||||
@@ -696,7 +703,7 @@ AS $export_logbook_gpx$
|
||||
AND m.longitude IS NOT NULL
|
||||
AND m.time >= log_rec._from_time::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND m.time <= log_rec._to_time::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = log_rec.client_id;
|
||||
AND vessel_id = log_rec.vessel_id;
|
||||
-- ERROR: column "m.time" must appear in the GROUP BY clause or be used in an aggregate function at character 2304
|
||||
--ORDER BY m.time ASC;
|
||||
END;
|
||||
@@ -808,14 +815,14 @@ COMMENT ON FUNCTION
|
||||
|
||||
-- trip_in_progress_fn
|
||||
DROP FUNCTION IF EXISTS public.trip_in_progress_fn;
|
||||
CREATE FUNCTION public.trip_in_progress_fn(IN _client_id TEXT) RETURNS INT AS $trip_in_progress$
|
||||
CREATE FUNCTION public.trip_in_progress_fn(IN _vessel_id TEXT) RETURNS INT AS $trip_in_progress$
|
||||
DECLARE
|
||||
logbook_id INT := NULL;
|
||||
BEGIN
|
||||
SELECT id INTO logbook_id
|
||||
FROM api.logbook l
|
||||
WHERE l.client_id IS NOT NULL
|
||||
AND l.client_id = _client_id
|
||||
WHERE l.vessel_id IS NOT NULL
|
||||
AND l.vessel_id = _vessel_id
|
||||
AND active IS true
|
||||
LIMIT 1;
|
||||
RETURN logbook_id;
|
||||
@@ -828,14 +835,14 @@ COMMENT ON FUNCTION
|
||||
|
||||
-- stay_in_progress_fn
|
||||
DROP FUNCTION IF EXISTS public.stay_in_progress_fn;
|
||||
CREATE FUNCTION public.stay_in_progress_fn(IN _client_id TEXT) RETURNS INT AS $stay_in_progress$
|
||||
CREATE FUNCTION public.stay_in_progress_fn(IN _vessel_id TEXT) RETURNS INT AS $stay_in_progress$
|
||||
DECLARE
|
||||
stay_id INT := NULL;
|
||||
BEGIN
|
||||
SELECT id INTO stay_id
|
||||
FROM api.stays s
|
||||
WHERE s.client_id IS NOT NULL
|
||||
AND s.client_id = _client_id
|
||||
WHERE s.vessel_id IS NOT NULL
|
||||
AND s.vessel_id = _vessel_id
|
||||
AND active IS true
|
||||
LIMIT 1;
|
||||
RETURN stay_id;
|
||||
@@ -1035,7 +1042,7 @@ COMMENT ON VIEW
|
||||
-- Stays web view
|
||||
-- TODO group by month
|
||||
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,
|
||||
concat(
|
||||
extract(DAYS FROM (s.departed-s.arrived)::interval),
|
||||
@@ -1068,7 +1075,7 @@ COMMENT ON VIEW
|
||||
IS 'Stays web 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,
|
||||
concat(
|
||||
extract(DAYS FROM (s.departed-s.arrived)::interval),
|
||||
@@ -1180,7 +1187,7 @@ COMMENT ON VIEW
|
||||
----> select sum(l.duration) as "Total Time Underway" from api.logbook l;
|
||||
-- Longest Nonstop Sail from logbook, eg longest trip duration and distance
|
||||
----> 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
|
||||
meta AS (
|
||||
SELECT m.name FROM api.metadata m ),
|
||||
@@ -1219,7 +1226,7 @@ COMMENT ON VIEW
|
||||
----> 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)
|
||||
----> 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
|
||||
home_ports AS (
|
||||
select count(*) as home_ports from api.moorages m where home_flag is true
|
||||
@@ -1243,7 +1250,7 @@ COMMENT ON VIEW
|
||||
api.stats_moorages_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
|
||||
FROM api.moorages m, api.stays_at sa
|
||||
WHERE home_flag IS false
|
||||
@@ -1269,7 +1276,8 @@ COMMENT ON VIEW
|
||||
-- IS 'Statistics Moorages Time Spent Away web view';
|
||||
|
||||
-- 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
|
||||
time AS "time",
|
||||
(NOW() AT TIME ZONE 'UTC' - time) > INTERVAL '70 MINUTES' as offline,
|
||||
@@ -1282,6 +1290,8 @@ CREATE VIEW api.monitoring_view WITH (security_invoker=true,security_barrier=tru
|
||||
metrics-> 'environment.outside.humidity' AS outsideHumidity,
|
||||
metrics-> 'environment.outside.pressure' AS outsidePressure,
|
||||
metrics-> 'environment.inside.pressure' AS insidePressure,
|
||||
metrics-> 'electrical.batteries.House.capacity.stateOfCharge' AS batteryCharge,
|
||||
metrics-> 'electrical.batteries.House.voltage' AS batteryVoltage,
|
||||
jsonb_build_object(
|
||||
'type', 'Feature',
|
||||
'geometry', ST_AsGeoJSON(st_makepoint(longitude,latitude))::jsonb,
|
||||
|
@@ -18,7 +18,7 @@ begin
|
||||
FOR process_rec in
|
||||
SELECT * FROM process_queue
|
||||
WHERE channel = 'new_logbook' AND processed IS NULL
|
||||
ORDER BY stored ASC
|
||||
ORDER BY stored ASC LIMIT 100
|
||||
LOOP
|
||||
RAISE NOTICE '-> cron_process_new_logbook_fn [%]', process_rec.payload;
|
||||
-- update logbook
|
||||
@@ -47,7 +47,7 @@ begin
|
||||
FOR process_rec in
|
||||
SELECT * FROM process_queue
|
||||
WHERE channel = 'new_stay' AND processed IS NULL
|
||||
ORDER BY stored ASC
|
||||
ORDER BY stored ASC LIMIT 100
|
||||
LOOP
|
||||
RAISE NOTICE '-> cron_process_new_stay_fn [%]', process_rec.payload;
|
||||
-- update stay
|
||||
@@ -77,7 +77,7 @@ begin
|
||||
FOR process_rec in
|
||||
SELECT * FROM process_queue
|
||||
WHERE channel = 'new_moorage' AND processed IS NULL
|
||||
ORDER BY stored ASC
|
||||
ORDER BY stored ASC LIMIT 100
|
||||
LOOP
|
||||
RAISE NOTICE '-> cron_process_new_moorage_fn [%]', process_rec.payload;
|
||||
-- update moorage
|
||||
@@ -124,30 +124,30 @@ begin
|
||||
active = False
|
||||
WHERE id = metadata_rec.id;
|
||||
|
||||
IF metadata_rec.client_id IS NULL OR metadata_rec.client_id = '' THEN
|
||||
RAISE WARNING '-> cron_process_monitor_offline_fn invalid metadata record client_id %', client_id;
|
||||
IF metadata_rec.vessel_id IS NULL OR metadata_rec.vessel_id = '' THEN
|
||||
RAISE WARNING '-> cron_process_monitor_offline_fn invalid metadata record vessel_id %', vessel_id;
|
||||
RAISE EXCEPTION 'Invalid metadata'
|
||||
USING HINT = 'Unknow client_id';
|
||||
USING HINT = 'Unknow vessel_id';
|
||||
RETURN;
|
||||
END IF;
|
||||
PERFORM set_config('vessel.client_id', metadata_rec.client_id, false);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_offline_fn vessel.client_id %', current_setting('vessel.client_id', false);
|
||||
RAISE NOTICE '-> cron_process_monitor_offline_fn updated api.metadata table to inactive for [%] [%]', metadata_rec.id, metadata_rec.client_id;
|
||||
PERFORM set_config('vessel.id', metadata_rec.vessel_id, false);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_offline_fn vessel.id %', current_setting('vessel.id', false);
|
||||
RAISE NOTICE '-> cron_process_monitor_offline_fn updated api.metadata table to inactive for [%] [%]', metadata_rec.id, metadata_rec.vessel_id;
|
||||
|
||||
-- Gather email and pushover app settings
|
||||
--app_settings = get_app_settings_fn();
|
||||
-- Gather user settings
|
||||
user_settings := get_user_settings_from_clientid_fn(metadata_rec.client_id::TEXT);
|
||||
RAISE DEBUG '-> cron_process_monitor_offline_fn get_user_settings_from_clientid_fn [%]', user_settings;
|
||||
user_settings := get_user_settings_from_vesselid_fn(metadata_rec.vessel_id::TEXT);
|
||||
RAISE DEBUG '-> cron_process_monitor_offline_fn get_user_settings_from_vesselid_fn [%]', user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('monitor_offline'::TEXT, user_settings::JSONB);
|
||||
--PERFORM send_email_py_fn('monitor_offline'::TEXT, user_settings::JSONB, app_settings::JSONB);
|
||||
--PERFORM send_pushover_py_fn('monitor_offline'::TEXT, user_settings::JSONB, app_settings::JSONB);
|
||||
-- log/insert/update process_queue table with processed
|
||||
INSERT INTO process_queue
|
||||
(channel, payload, stored, processed)
|
||||
(channel, payload, stored, processed, ref_id)
|
||||
VALUES
|
||||
('monitoring_offline', metadata_rec.id, metadata_rec.interval, now())
|
||||
('monitoring_offline', metadata_rec.id, metadata_rec.interval, now(), metadata_rec.vessel_id)
|
||||
RETURNING id INTO process_id;
|
||||
RAISE NOTICE '-> cron_process_monitor_offline_fn updated process_queue table [%]', process_id;
|
||||
END LOOP;
|
||||
@@ -174,25 +174,25 @@ begin
|
||||
where channel = 'monitoring_online' and processed is null
|
||||
order by stored asc
|
||||
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
|
||||
FROM api.metadata
|
||||
WHERE id = process_rec.payload::INTEGER;
|
||||
|
||||
IF metadata_rec.client_id IS NULL OR metadata_rec.client_id = '' THEN
|
||||
RAISE WARNING '-> cron_process_monitor_online_fn invalid metadata record client_id %', client_id;
|
||||
IF metadata_rec.vessel_id IS NULL OR metadata_rec.vessel_id = '' THEN
|
||||
RAISE WARNING '-> cron_process_monitor_online_fn invalid metadata record vessel_id %', vessel_id;
|
||||
RAISE EXCEPTION 'Invalid metadata'
|
||||
USING HINT = 'Unknow client_id';
|
||||
USING HINT = 'Unknow vessel_id';
|
||||
RETURN;
|
||||
END IF;
|
||||
PERFORM set_config('vessel.client_id', metadata_rec.client_id, false);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_online_fn vessel.client_id %', current_setting('vessel.client_id', false);
|
||||
PERFORM set_config('vessel.id', metadata_rec.vessel_id, false);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_online_fn vessel_id %', current_setting('vessel.id', false);
|
||||
|
||||
-- Gather email and pushover app settings
|
||||
--app_settings = get_app_settings_fn();
|
||||
-- Gather user settings
|
||||
user_settings := get_user_settings_from_clientid_fn(metadata_rec.client_id::TEXT);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_online_fn get_user_settings_from_clientid_fn [%]', user_settings;
|
||||
user_settings := get_user_settings_from_vesselid_fn(metadata_rec.vessel_id::TEXT);
|
||||
RAISE DEBUG '-> DEBUG cron_process_monitor_online_fn get_user_settings_from_vesselid_fn [%]', user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('monitor_online'::TEXT, user_settings::JSONB);
|
||||
--PERFORM send_email_py_fn('monitor_online'::TEXT, user_settings::JSONB, app_settings::JSONB);
|
||||
@@ -238,7 +238,7 @@ $$ language plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.cron_process_new_account_fn
|
||||
IS 'init by pg_cron to check for new account pending update, if so perform process_account_queue_fn';
|
||||
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
|
||||
CREATE FUNCTION cron_process_new_account_otp_validation_fn() RETURNS void AS $$
|
||||
@@ -267,7 +267,7 @@ $$ language plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
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
|
||||
CREATE FUNCTION cron_process_new_vessel_fn() RETURNS void AS $$
|
||||
@@ -296,7 +296,7 @@ $$ language plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.cron_process_new_vessel_fn
|
||||
IS 'init by pg_cron to check for new vessel pending update, if so perform process_vessel_queue_fn';
|
||||
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
|
||||
CREATE FUNCTION cron_process_new_notification_fn() RETURNS void AS $$
|
||||
@@ -362,3 +362,27 @@ $$ language plpgsql;
|
||||
COMMENT ON FUNCTION
|
||||
public.cron_vaccum_fn
|
||||
IS 'init by pg_cron to cleanup job_run_details table on schema public postgras db';
|
||||
|
||||
-- CRON for alerts notification
|
||||
CREATE FUNCTION cron_process_alerts_fn() RETURNS void AS $$
|
||||
DECLARE
|
||||
alert_rec record;
|
||||
BEGIN
|
||||
-- Check for new event notification pending update
|
||||
RAISE NOTICE 'cron_process_alerts_fn';
|
||||
FOR alert_rec in
|
||||
SELECT
|
||||
a.user_id,a.email,v.vessel_id
|
||||
FROM auth.accounts a, auth.vessels v, api.metadata m
|
||||
WHERE m.vessel_id = v.vessel_id
|
||||
AND a.email = v.owner_email
|
||||
AND (preferences->'alerting'->'enabled')::boolean = false
|
||||
LOOP
|
||||
RAISE NOTICE '-> cron_process_alert_rec_fn for [%]', alert_rec;
|
||||
END LOOP;
|
||||
END;
|
||||
$$ language plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.cron_process_alerts_fn
|
||||
IS 'init by pg_cron to check for alerts, if so perform process_alerts_queue_fn';
|
||||
|
@@ -36,7 +36,8 @@ INSERT INTO geocoders VALUES
|
||||
---------------------------------------------------------------------------
|
||||
-- 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,
|
||||
email_subject TEXT,
|
||||
email_content TEXT,
|
||||
@@ -94,7 +95,7 @@ INSERT INTO email_templates VALUES
|
||||
E'Congratulations!\nPlease validate your account. Check your email!'),
|
||||
('email_valid',
|
||||
'Email verified',
|
||||
E'Hello __RECIPIENT__,\nCongratulations!\nYou successfully validate your account.\nThe PostgSail Team',
|
||||
E'Hello,\nCongratulations!\nYou successfully validate your account.\nThe PostgSail Team',
|
||||
'Email verified',
|
||||
E'Hi!\nYou successfully validate your account.\n'),
|
||||
('email_reset',
|
||||
@@ -104,9 +105,9 @@ INSERT INTO email_templates VALUES
|
||||
E'You requested a password recovery. Check your email!\n'),
|
||||
('telegram_otp',
|
||||
'Telegram bot',
|
||||
E'Hello __RECIPIENT__,\nTo connect your account to a @postgsail_bot. Please type this verification code __OTP_CODE__ back to the bot.\nThe code is valid 15 minutes.\nThe PostgSail Team',
|
||||
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',
|
||||
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 bot',
|
||||
E'Hello __RECIPIENT__,\nCongratulations! You have just connect your account to your vessel, @postgsail_bot.\n\nThe PostgSail Team',
|
||||
@@ -132,6 +133,7 @@ CREATE TABLE IF NOT EXISTS public.process_queue (
|
||||
id SERIAL PRIMARY KEY,
|
||||
channel TEXT NOT NULL,
|
||||
payload TEXT NOT NULL,
|
||||
ref_id TEXT NOT NULL,
|
||||
stored TIMESTAMP WITHOUT TIME ZONE NOT NULL,
|
||||
processed TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL
|
||||
);
|
||||
@@ -144,24 +146,26 @@ CREATE INDEX ON public.process_queue (channel);
|
||||
CREATE INDEX ON public.process_queue (stored);
|
||||
CREATE INDEX ON public.process_queue (processed);
|
||||
|
||||
COMMENT ON COLUMN public.process_queue.ref_id IS 'either user_id or vessel_id';
|
||||
|
||||
-- Function process_queue helpers
|
||||
create function new_account_entry_fn() returns trigger as $new_account_entry$
|
||||
begin
|
||||
insert into process_queue (channel, payload, stored) values ('new_account', NEW.email, now());
|
||||
insert into process_queue (channel, payload, stored, ref_id) values ('new_account', NEW.email, now(), NEW.user_id);
|
||||
return NEW;
|
||||
END;
|
||||
$new_account_entry$ language plpgsql;
|
||||
|
||||
create function new_account_otp_validation_entry_fn() returns trigger as $new_account_otp_validation_entry$
|
||||
begin
|
||||
insert into process_queue (channel, payload, stored) values ('email_otp', NEW.email, now());
|
||||
insert into process_queue (channel, payload, stored, ref_id) values ('email_otp', NEW.email, now(), NEW.user_id);
|
||||
return NEW;
|
||||
END;
|
||||
$new_account_otp_validation_entry$ language plpgsql;
|
||||
|
||||
create function new_vessel_entry_fn() returns trigger as $new_vessel_entry$
|
||||
begin
|
||||
insert into process_queue (channel, payload, stored) values ('new_vessel', NEW.owner_email, now());
|
||||
insert into process_queue (channel, payload, stored, ref_id) values ('new_vessel', NEW.owner_email, now(), NEW.vessel_id);
|
||||
return NEW;
|
||||
END;
|
||||
$new_vessel_entry$ language plpgsql;
|
||||
@@ -183,9 +187,9 @@ COMMENT ON COLUMN public.app_settings.value IS 'application settings value';
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- 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,
|
||||
description TEXT
|
||||
);
|
||||
@@ -205,25 +209,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!'),
|
||||
('Anchormaster',
|
||||
'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é!'),
|
||||
('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! '),
|
||||
('Club Alaska',
|
||||
'Home to the bears, glaciers, midnight sun and high adventure. Welcome to the Club Alaska Captain!'),
|
||||
('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',
|
||||
'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',
|
||||
'You made it to the Tyee Outstation, the friendliest dock in Pacific Northwest!'),
|
||||
-- TODO the sea is big and the world is not limited to the US
|
||||
('Mediterranean Traveler',
|
||||
'You made it trought the Mediterranean!');
|
||||
'Ticking off over 2300 NM across the great blue Pacific makes you the rare recipient of the Aloha Award. Well done and Aloha sailor!'),
|
||||
('Navigator Award',
|
||||
'Woohoo! You made it, Ticking off over 100NM in one go, well done sailor!'),
|
||||
('Captain Award',
|
||||
'Congratulation, you reach over 1000NM, well done sailor!');
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- aistypes description
|
||||
--
|
||||
DROP TABLE IF EXISTS public.aistypes;
|
||||
CREATE TABLE IF NOT EXISTS aistypes(
|
||||
id NUMERIC UNIQUE,
|
||||
description TEXT
|
||||
@@ -319,9 +323,11 @@ INSERT INTO aistypes VALUES
|
||||
---------------------------------------------------------------------------
|
||||
-- MMSI MID Codes
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS mid(
|
||||
DROP TABLE IF EXISTS public.mid;
|
||||
CREATE TABLE IF NOT EXISTS public.mid(
|
||||
country TEXT,
|
||||
id NUMERIC UNIQUE
|
||||
id NUMERIC UNIQUE,
|
||||
country_id INTEGER
|
||||
);
|
||||
-- Description
|
||||
COMMENT ON TABLE
|
||||
@@ -329,292 +335,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';
|
||||
|
||||
INSERT INTO mid VALUES
|
||||
('Adelie Land', 501),
|
||||
('Afghanistan', 401),
|
||||
('Alaska', 303),
|
||||
('Albania', 201),
|
||||
('Algeria', 605),
|
||||
('American Samoa', 559),
|
||||
('Andorra', 202),
|
||||
('Angola', 603),
|
||||
('Anguilla', 301),
|
||||
('Antigua and Barbuda', 304),
|
||||
('Antigua and Barbuda', 305),
|
||||
('Argentina', 701),
|
||||
('Armenia', 216),
|
||||
('Aruba', 307),
|
||||
('Ascension Island', 608),
|
||||
('Australia', 503),
|
||||
('Austria', 203),
|
||||
('Azerbaijan', 423),
|
||||
('Azores', 204),
|
||||
('Bahamas', 308),
|
||||
('Bahamas', 309),
|
||||
('Bahamas', 311),
|
||||
('Bahrain', 408),
|
||||
('Bangladesh', 405),
|
||||
('Barbados', 314),
|
||||
('Belarus', 206),
|
||||
('Belgium', 205),
|
||||
('Belize', 312),
|
||||
('Benin', 610),
|
||||
('Bermuda', 310),
|
||||
('Bhutan', 410),
|
||||
('Bolivia', 720),
|
||||
('Bosnia and Herzegovina', 478),
|
||||
('Botswana', 611),
|
||||
('Brazil', 710),
|
||||
('British Virgin Islands', 378),
|
||||
('Brunei Darussalam', 508),
|
||||
('Bulgaria', 207),
|
||||
('Burkina Faso', 633),
|
||||
('Burundi', 609),
|
||||
('Cambodia', 514),
|
||||
('Cambodia', 515),
|
||||
('Cameroon', 613),
|
||||
('Canada', 316),
|
||||
('Cape Verde', 617),
|
||||
('Cayman Islands', 319),
|
||||
('Central African Republic', 612),
|
||||
('Chad', 670),
|
||||
('Chile', 725),
|
||||
('China', 412),
|
||||
('China', 413),
|
||||
('China', 414),
|
||||
('Christmas Island', 516),
|
||||
('Cocos Islands', 523),
|
||||
('Colombia', 730),
|
||||
('Comoros', 616),
|
||||
('Comoros', 620),
|
||||
('Congo', 615),
|
||||
('Cook Islands', 518),
|
||||
('Costa Rica', 321),
|
||||
(E'Côte d\'Ivoire', 619),
|
||||
('Croatia', 238),
|
||||
('Crozet Archipelago', 618),
|
||||
('Cuba', 323),
|
||||
('Cyprus', 209),
|
||||
('Cyprus', 210),
|
||||
('Cyprus', 212),
|
||||
('Czech Republic', 270),
|
||||
('Denmark', 219),
|
||||
('Denmark', 220),
|
||||
('Djibouti', 621),
|
||||
('Dominica', 325),
|
||||
('Dominican Republic', 327),
|
||||
('DR Congo', 676),
|
||||
('Ecuador', 735),
|
||||
('Egypt', 622),
|
||||
('El Salvador', 359),
|
||||
('Equatorial Guinea', 631),
|
||||
('Eritrea', 625),
|
||||
('Estonia', 276),
|
||||
('Ethiopia', 624),
|
||||
('Falkland Islands', 740),
|
||||
('Faroe Islands', 231),
|
||||
('Fiji', 520),
|
||||
('Finland', 230),
|
||||
('France', 226),
|
||||
('France', 227),
|
||||
('France', 228),
|
||||
('French Polynesia', 546),
|
||||
('Gabonese Republic', 626),
|
||||
('Gambia', 629),
|
||||
('Georgia', 213),
|
||||
('Germany', 211),
|
||||
('Germany', 218),
|
||||
('Ghana', 627),
|
||||
('Gibraltar', 236),
|
||||
('Greece', 237),
|
||||
('Greece', 239),
|
||||
('Greece', 240),
|
||||
('Greece', 241),
|
||||
('Greenland', 331),
|
||||
('Grenada', 330),
|
||||
('Guadeloupe', 329),
|
||||
('Guatemala', 332),
|
||||
('Guiana', 745),
|
||||
('Guinea', 632),
|
||||
('Guinea-Bissau', 630),
|
||||
('Guyana', 750),
|
||||
('Haiti', 336),
|
||||
('Honduras', 334),
|
||||
('Hong Kong', 477),
|
||||
('Hungary', 243),
|
||||
('Iceland', 251),
|
||||
('India', 419),
|
||||
('Indonesia', 525),
|
||||
('Iran', 422),
|
||||
('Iraq', 425),
|
||||
('Ireland', 250),
|
||||
('Israel', 428),
|
||||
('Italy', 247),
|
||||
('Jamaica', 339),
|
||||
('Japan', 431),
|
||||
('Japan', 432),
|
||||
('Jordan', 438),
|
||||
('Kazakhstan', 436),
|
||||
('Kenya', 634),
|
||||
('Kerguelen Islands', 635),
|
||||
('Kiribati', 529),
|
||||
('Kuwait', 447),
|
||||
('Kyrgyzstan', 451),
|
||||
('Lao', 531),
|
||||
('Latvia', 275),
|
||||
('Lebanon', 450),
|
||||
('Lesotho', 644),
|
||||
('Liberia', 636),
|
||||
('Liberia', 637),
|
||||
('Libya', 642),
|
||||
('Liechtenstein', 252),
|
||||
('Lithuania', 277),
|
||||
('Luxembourg', 253),
|
||||
('Macao', 453),
|
||||
('Madagascar', 647),
|
||||
('Madeira', 255),
|
||||
('Makedonia', 274),
|
||||
('Malawi', 655),
|
||||
('Malaysia', 533),
|
||||
('Maldives', 455),
|
||||
('Mali', 649),
|
||||
('Malta', 215),
|
||||
('Malta', 229),
|
||||
('Malta', 248),
|
||||
('Malta', 249),
|
||||
('Malta', 256),
|
||||
('Marshall Islands', 538),
|
||||
('Martinique', 347),
|
||||
('Mauritania', 654),
|
||||
('Mauritius', 645),
|
||||
('Mexico', 345),
|
||||
('Micronesia', 510),
|
||||
('Moldova', 214),
|
||||
('Monaco', 254),
|
||||
('Mongolia', 457),
|
||||
('Montenegro', 262),
|
||||
('Montserrat', 348),
|
||||
('Morocco', 242),
|
||||
('Mozambique', 650),
|
||||
('Myanmar', 506),
|
||||
('Namibia', 659),
|
||||
('Nauru', 544),
|
||||
('Nepal', 459),
|
||||
('Netherlands', 244),
|
||||
('Netherlands', 245),
|
||||
('Netherlands', 246),
|
||||
('Netherlands Antilles', 306),
|
||||
('New Caledonia', 540),
|
||||
('New Zealand', 512),
|
||||
('Nicaragua', 350),
|
||||
('Niger', 656),
|
||||
('Nigeria', 657),
|
||||
('Niue', 542),
|
||||
('North Korea', 445),
|
||||
('Northern Mariana Islands', 536),
|
||||
('Norway', 257),
|
||||
('Norway', 258),
|
||||
('Norway', 259),
|
||||
('Oman', 461),
|
||||
('Pakistan', 463),
|
||||
('Palau', 511),
|
||||
('Palestine', 443),
|
||||
('Panama', 351),
|
||||
('Panama', 352),
|
||||
('Panama', 353),
|
||||
('Panama', 354),
|
||||
('Panama', 355),
|
||||
('Panama', 356),
|
||||
('Panama', 357),
|
||||
('Panama', 370),
|
||||
('Panama', 371),
|
||||
('Panama', 372),
|
||||
('Panama', 373),
|
||||
('Papua New Guinea', 553),
|
||||
('Paraguay', 755),
|
||||
('Peru', 760),
|
||||
('Philippines', 548),
|
||||
('Pitcairn Island', 555),
|
||||
('Poland', 261),
|
||||
('Portugal', 263),
|
||||
('Puerto Rico', 358),
|
||||
('Qatar', 466),
|
||||
('Reunion', 660),
|
||||
('Romania', 264),
|
||||
('Russian Federation', 273),
|
||||
('Rwanda', 661),
|
||||
('Saint Helena', 665),
|
||||
('Saint Kitts and Nevis', 341),
|
||||
('Saint Lucia', 343),
|
||||
('Saint Paul and Amsterdam Islands', 607),
|
||||
('Saint Pierre and Miquelon', 361),
|
||||
('Samoa', 561),
|
||||
('San Marino', 268),
|
||||
('Sao Tome and Principe', 668),
|
||||
('Saudi Arabia', 403),
|
||||
('Senegal', 663),
|
||||
('Serbia', 279),
|
||||
('Seychelles', 664),
|
||||
('Sierra Leone', 667),
|
||||
('Singapore', 563),
|
||||
('Singapore', 564),
|
||||
('Singapore', 565),
|
||||
('Singapore', 566),
|
||||
('Slovakia', 267),
|
||||
('Slovenia', 278),
|
||||
('Solomon Islands', 557),
|
||||
('Somalia', 666),
|
||||
('South Africa', 601),
|
||||
('South Korea', 440),
|
||||
('South Korea', 441),
|
||||
('South Sudan', 638),
|
||||
('Spain', 224),
|
||||
('Spain', 225),
|
||||
('Sri Lanka', 417),
|
||||
('St Vincent and the Grenadines', 375),
|
||||
('St Vincent and the Grenadines', 376),
|
||||
('St Vincent and the Grenadines', 377),
|
||||
('Sudan', 662),
|
||||
('Suriname', 765),
|
||||
('Swaziland', 669),
|
||||
('Sweden', 265),
|
||||
('Sweden', 266),
|
||||
('Switzerland', 269),
|
||||
('Syria', 468),
|
||||
('Taiwan', 416),
|
||||
('Tajikistan', 472),
|
||||
('Tanzania', 674),
|
||||
('Tanzania', 677),
|
||||
('Thailand', 567),
|
||||
('Togolese', 671),
|
||||
('Tonga', 570),
|
||||
('Trinidad and Tobago', 362),
|
||||
('Tunisia', 672),
|
||||
('Turkey', 271),
|
||||
('Turkmenistan', 434),
|
||||
('Turks and Caicos Islands', 364),
|
||||
('Tuvalu', 572),
|
||||
('Uganda', 675),
|
||||
('Ukraine', 272),
|
||||
('United Arab Emirates', 470),
|
||||
('United Kingdom', 232),
|
||||
('United Kingdom', 233),
|
||||
('United Kingdom', 234),
|
||||
('United Kingdom', 235),
|
||||
('Uruguay', 770),
|
||||
('US Virgin Islands', 379),
|
||||
('USA', 338),
|
||||
('USA', 366),
|
||||
('USA', 367),
|
||||
('USA', 368),
|
||||
('USA', 369),
|
||||
('Uzbekistan', 437),
|
||||
('Vanuatu', 576),
|
||||
('Vanuatu', 577),
|
||||
('Vatican City', 208),
|
||||
('Venezuela', 775),
|
||||
('Vietnam', 574),
|
||||
('Wallis and Futuna Islands', 578),
|
||||
('Yemen', 473),
|
||||
('Yemen', 475),
|
||||
('Zambia', 678),
|
||||
('Zimbabwe', 679);
|
||||
('Adelie Land', 501, NULL),
|
||||
('Afghanistan', 401, 4),
|
||||
('Alaska', 303, 840),
|
||||
('Albania', 201, 8),
|
||||
('Algeria', 605, 12),
|
||||
('American Samoa', 559, 16),
|
||||
('Andorra', 202, 20),
|
||||
('Angola', 603, 24),
|
||||
('Anguilla', 301, 660),
|
||||
('Antigua and Barbuda', 304, 28),
|
||||
('Antigua and Barbuda', 305, 28),
|
||||
('Argentina', 701, 32),
|
||||
('Armenia', 216, 51),
|
||||
('Aruba', 307, 533),
|
||||
('Ascension Island', 608, NULL),
|
||||
('Australia', 503, 36),
|
||||
('Austria', 203, 40),
|
||||
('Azerbaijan', 423, 31),
|
||||
('Azores', 204, NULL),
|
||||
('Bahamas', 308, 44),
|
||||
('Bahamas', 309, 44),
|
||||
('Bahamas', 311, 44),
|
||||
('Bahrain', 408, 48),
|
||||
('Bangladesh', 405, 50),
|
||||
('Barbados', 314, 52),
|
||||
('Belarus', 206, 112),
|
||||
('Belgium', 205, 56),
|
||||
('Belize', 312, 84),
|
||||
('Benin', 610, 204),
|
||||
('Bermuda', 310, 60),
|
||||
('Bhutan', 410, 64),
|
||||
('Bolivia', 720, 68),
|
||||
('Bosnia and Herzegovina', 478, 70),
|
||||
('Botswana', 611, 72),
|
||||
('Brazil', 710, 76),
|
||||
('British Virgin Islands', 378, 92),
|
||||
('Brunei Darussalam', 508, 96),
|
||||
('Bulgaria', 207, 100),
|
||||
('Burkina Faso', 633, 854),
|
||||
('Burundi', 609, 108),
|
||||
('Cambodia', 514, 116),
|
||||
('Cambodia', 515, 116),
|
||||
('Cameroon', 613, 120),
|
||||
('Canada', 316, 124),
|
||||
('Cape Verde', 617, 132),
|
||||
('Cayman Islands', 319, 136),
|
||||
('Central African Republic', 612, 140),
|
||||
('Chad', 670, 148),
|
||||
('Chile', 725, 152),
|
||||
('China', 412, 156),
|
||||
('China', 413, 156),
|
||||
('China', 414, 156),
|
||||
('Christmas Island', 516, 162),
|
||||
('Cocos Islands', 523, 166),
|
||||
('Colombia', 730, 170),
|
||||
('Comoros', 616, 174),
|
||||
('Comoros', 620, 174),
|
||||
('Congo', 615, 178),
|
||||
('Cook Islands', 518, 184),
|
||||
('Costa Rica', 321, 188),
|
||||
(E'Côte d\'Ivoire', 619, 384),
|
||||
('Croatia', 238, 191),
|
||||
('Crozet Archipelago', 618, NULL),
|
||||
('Cuba', 323, 192),
|
||||
('Cyprus', 209, 196),
|
||||
('Cyprus', 210, 196),
|
||||
('Cyprus', 212, 196),
|
||||
('Czech Republic', 270, 203),
|
||||
('Denmark', 219, 208),
|
||||
('Denmark', 220, 208),
|
||||
('Djibouti', 621, 262),
|
||||
('Dominica', 325, 212),
|
||||
('Dominican Republic', 327, 214),
|
||||
('DR Congo', 676, NULL),
|
||||
('Ecuador', 735, 218),
|
||||
('Egypt', 622, 818),
|
||||
('El Salvador', 359, 222),
|
||||
('Equatorial Guinea', 631, 226),
|
||||
('Eritrea', 625, 232),
|
||||
('Estonia', 276, 233),
|
||||
('Ethiopia', 624, 231),
|
||||
('Falkland Islands', 740, 234),
|
||||
('Faroe Islands', 231, NULL),
|
||||
('Fiji', 520, 242),
|
||||
('Finland', 230, 246),
|
||||
('France', 226, 250),
|
||||
('France', 227, 250),
|
||||
('France', 228, 250),
|
||||
('French Polynesia', 546, 260),
|
||||
('Gabonese Republic', 626, 266),
|
||||
('Gambia', 629, 270),
|
||||
('Georgia', 213, 268),
|
||||
('Germany', 211, 276),
|
||||
('Germany', 218, 276),
|
||||
('Ghana', 627, 288),
|
||||
('Gibraltar', 236, 292),
|
||||
('Greece', 237, 300),
|
||||
('Greece', 239, 300),
|
||||
('Greece', 240, 300),
|
||||
('Greece', 241, 300),
|
||||
('Greenland', 331, 304),
|
||||
('Grenada', 330, 308),
|
||||
('Guadeloupe', 329, 312),
|
||||
('Guatemala', 332, 320),
|
||||
('Guiana', 745, 324),
|
||||
('Guinea', 632, 324),
|
||||
('Guinea-Bissau', 630, 624),
|
||||
('Guyana', 750, 328),
|
||||
('Haiti', 336, 332),
|
||||
('Honduras', 334, 340),
|
||||
('Hong Kong', 477, 344),
|
||||
('Hungary', 243, 348),
|
||||
('Iceland', 251, 352),
|
||||
('India', 419, 356),
|
||||
('Indonesia', 525, 360),
|
||||
('Iran', 422, 364),
|
||||
('Iraq', 425, 368),
|
||||
('Ireland', 250, 372),
|
||||
('Israel', 428, 376),
|
||||
('Italy', 247, 380),
|
||||
('Jamaica', 339, 388),
|
||||
('Japan', 431, 392),
|
||||
('Japan', 432, 392),
|
||||
('Jordan', 438, 400),
|
||||
('Kazakhstan', 436, 398),
|
||||
('Kenya', 634, 404),
|
||||
('Kerguelen Islands', 635, NULL),
|
||||
('Kiribati', 529, 296),
|
||||
('Kuwait', 447, 414),
|
||||
('Kyrgyzstan', 451, 417),
|
||||
('Lao', 531, 418),
|
||||
('Latvia', 275, 428),
|
||||
('Lebanon', 450, 422),
|
||||
('Lesotho', 644, 426),
|
||||
('Liberia', 636, 430),
|
||||
('Liberia', 637, 430),
|
||||
('Libya', 642, 434),
|
||||
('Liechtenstein', 252, 438),
|
||||
('Lithuania', 277, 440),
|
||||
('Luxembourg', 253, 442),
|
||||
('Macao', 453, 446),
|
||||
('Madagascar', 647, 450),
|
||||
('Madeira', 255, NULL),
|
||||
('Makedonia', 274, NULL),
|
||||
('Malawi', 655, 454),
|
||||
('Malaysia', 533, 458),
|
||||
('Maldives', 455, 462),
|
||||
('Mali', 649, 466),
|
||||
('Malta', 215, 470),
|
||||
('Malta', 229, 470),
|
||||
('Malta', 248, 470),
|
||||
('Malta', 249, 470),
|
||||
('Malta', 256, 470),
|
||||
('Marshall Islands', 538, 584),
|
||||
('Martinique', 347, 474),
|
||||
('Mauritania', 654, 478),
|
||||
('Mauritius', 645, 480),
|
||||
('Mexico', 345, 484),
|
||||
('Micronesia', 510, 583),
|
||||
('Moldova', 214, 498),
|
||||
('Monaco', 254, 492),
|
||||
('Mongolia', 457, 496),
|
||||
('Montenegro', 262, 499),
|
||||
('Montserrat', 348, 500),
|
||||
('Morocco', 242, 504),
|
||||
('Mozambique', 650, 508),
|
||||
('Myanmar', 506, 104),
|
||||
('Namibia', 659, 516),
|
||||
('Nauru', 544, 520),
|
||||
('Nepal', 459, 524),
|
||||
('Netherlands', 244, 528),
|
||||
('Netherlands', 245, 528),
|
||||
('Netherlands', 246, 528),
|
||||
('Netherlands Antilles', 306, NULL),
|
||||
('New Caledonia', 540, 540),
|
||||
('New Zealand', 512, 554),
|
||||
('Nicaragua', 350, 558),
|
||||
('Niger', 656, 562),
|
||||
('Nigeria', 657, 566),
|
||||
('Niue', 542, 570),
|
||||
('North Korea', 445, 408),
|
||||
('Northern Mariana Islands', 536, 580),
|
||||
('Norway', 257, 578),
|
||||
('Norway', 258, 578),
|
||||
('Norway', 259, 578),
|
||||
('Oman', 461, 512),
|
||||
('Pakistan', 463, 586),
|
||||
('Palau', 511, 585),
|
||||
('Palestine', 443, 275),
|
||||
('Panama', 351, 591),
|
||||
('Panama', 352, 591),
|
||||
('Panama', 353, 591),
|
||||
('Panama', 354, 591),
|
||||
('Panama', 355, 591),
|
||||
('Panama', 356, 591),
|
||||
('Panama', 357, 591),
|
||||
('Panama', 370, 591),
|
||||
('Panama', 371, 591),
|
||||
('Panama', 372, 591),
|
||||
('Panama', 373, 591),
|
||||
('Papua New Guinea', 553, 598),
|
||||
('Paraguay', 755, 600),
|
||||
('Peru', 760, 604),
|
||||
('Philippines', 548, 608),
|
||||
('Pitcairn Island', 555, 612),
|
||||
('Poland', 261, 616),
|
||||
('Portugal', 263, 620),
|
||||
('Puerto Rico', 358, 630),
|
||||
('Qatar', 466, 634),
|
||||
('Reunion', 660, 638),
|
||||
('Romania', 264, 642),
|
||||
('Russian Federation', 273, 643),
|
||||
('Rwanda', 661, 646),
|
||||
('Saint Helena', 665, 654),
|
||||
('Saint Kitts and Nevis', 341, 659),
|
||||
('Saint Lucia', 343, 662),
|
||||
('Saint Paul and Amsterdam Islands', 607, NULL),
|
||||
('Saint Pierre and Miquelon', 361, 666),
|
||||
('Samoa', 561, 882),
|
||||
('San Marino', 268, 674),
|
||||
('Sao Tome and Principe', 668, 678),
|
||||
('Saudi Arabia', 403, 682),
|
||||
('Senegal', 663, 686),
|
||||
('Serbia', 279, 688),
|
||||
('Seychelles', 664, 690),
|
||||
('Sierra Leone', 667, 694),
|
||||
('Singapore', 563, 702),
|
||||
('Singapore', 564, 702),
|
||||
('Singapore', 565, 702),
|
||||
('Singapore', 566, 702),
|
||||
('Slovakia', 267, 703),
|
||||
('Slovenia', 278, 705),
|
||||
('Solomon Islands', 557, 90),
|
||||
('Somalia', 666, 706),
|
||||
('South Africa', 601, 710),
|
||||
('South Korea', 440, 410),
|
||||
('South Korea', 441, 410),
|
||||
('South Sudan', 638, 728),
|
||||
('Spain', 224, 724),
|
||||
('Spain', 225, 724),
|
||||
('Sri Lanka', 417, 144),
|
||||
('St Vincent and the Grenadines', 375, 670),
|
||||
('St Vincent and the Grenadines', 376, 670),
|
||||
('St Vincent and the Grenadines', 377, 670),
|
||||
('Sudan', 662, 729),
|
||||
('Suriname', 765, 740),
|
||||
('Swaziland', 669, 748),
|
||||
('Sweden', 265, 752),
|
||||
('Sweden', 266, 752),
|
||||
('Switzerland', 269, 756),
|
||||
('Syria', 468, 760),
|
||||
('Taiwan', 416, 158),
|
||||
('Tajikistan', 472, 762),
|
||||
('Tanzania', 674, 834),
|
||||
('Tanzania', 677, 834),
|
||||
('Thailand', 567, 764),
|
||||
('Togolese', 671, 768),
|
||||
('Tonga', 570, 776),
|
||||
('Trinidad and Tobago', 362, 780),
|
||||
('Tunisia', 672, 788),
|
||||
('Turkey', 271, 792),
|
||||
('Turkmenistan', 434, 795),
|
||||
('Turks and Caicos Islands', 364, 796),
|
||||
('Tuvalu', 572, 798),
|
||||
('Uganda', 675, 800),
|
||||
('Ukraine', 272, 804),
|
||||
('United Arab Emirates', 470, 784),
|
||||
('United Kingdom', 232, 826),
|
||||
('United Kingdom', 233, 826),
|
||||
('United Kingdom', 234, 826),
|
||||
('United Kingdom', 235, 826),
|
||||
('Uruguay', 770, 858),
|
||||
('US Virgin Islands', 379, 850),
|
||||
('USA', 338, 840),
|
||||
('USA', 366, 840),
|
||||
('USA', 367, 840),
|
||||
('USA', 368, 840),
|
||||
('USA', 369, 840),
|
||||
('Uzbekistan', 437, 860),
|
||||
('Vanuatu', 576, 548),
|
||||
('Vanuatu', 577, 548),
|
||||
('Vatican City', 208, NULL),
|
||||
('Venezuela', 775, 862),
|
||||
('Vietnam', 574, 704),
|
||||
('Wallis and Futuna Islands', 578, 876),
|
||||
('Yemen', 473, 887),
|
||||
('Yemen', 475, 887),
|
||||
('Zambia', 678, 894),
|
||||
('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');
|
||||
|
@@ -12,7 +12,7 @@ CREATE SCHEMA IF NOT EXISTS public;
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- 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(
|
||||
@@ -29,7 +29,7 @@ CREATE OR REPLACE FUNCTION logbook_metrics_dwithin_fn(
|
||||
AND m.longitude IS NOT NULL
|
||||
AND m.time >= _start::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND m.time <= _end::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = current_setting('vessel.client_id', false)
|
||||
AND vessel_id = current_setting('vessel.id', false)
|
||||
AND ST_DWithin(
|
||||
Geography(ST_MakePoint(m.longitude, m.latitude)),
|
||||
Geography(ST_MakePoint(lgn, lat)),
|
||||
@@ -62,7 +62,7 @@ CREATE OR REPLACE FUNCTION logbook_update_avg_fn(
|
||||
AND m.longitude IS NOT NULL
|
||||
AND m.time >= _start::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND m.time <= _end::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = current_setting('vessel.client_id', false);
|
||||
AND vessel_id = current_setting('vessel.id', false);
|
||||
RAISE NOTICE '-> Updated avg for logbook id=%, avg_speed:%, max_speed:%, max_wind_speed:%, count:%', _id, avg_speed, max_speed, max_wind_speed, count_metric;
|
||||
END;
|
||||
$logbook_update_avg$ LANGUAGE plpgsql;
|
||||
@@ -89,7 +89,7 @@ CREATE FUNCTION logbook_update_geom_distance_fn(IN _id integer, IN _start text,
|
||||
AND m.longitude IS NOT NULL
|
||||
AND m.time >= _start::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND m.time <= _end::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = current_setting('vessel.client_id', false)
|
||||
AND vessel_id = current_setting('vessel.id', false)
|
||||
ORDER BY m.time ASC
|
||||
)
|
||||
) INTO _track_geom;
|
||||
@@ -150,7 +150,7 @@ CREATE FUNCTION logbook_update_geojson_fn(IN _id integer, IN _start text, IN _en
|
||||
AND m.longitude IS NOT NULL
|
||||
AND time >= _start::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND time <= _end::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = current_setting('vessel.client_id', false)
|
||||
AND vessel_id = current_setting('vessel.id', false)
|
||||
ORDER BY m.time ASC
|
||||
)
|
||||
) AS t;
|
||||
@@ -207,13 +207,13 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
|
||||
AND _to_lng IS NOT NULL
|
||||
AND _to_lat IS NOT NULL;
|
||||
-- Ensure the query is successful
|
||||
IF logbook_rec.client_id IS NULL THEN
|
||||
IF logbook_rec.vessel_id IS NULL THEN
|
||||
RAISE WARNING '-> process_logbook_queue_fn invalid logbook %', _id;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
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);
|
||||
PERFORM set_config('vessel.id', logbook_rec.vessel_id, false);
|
||||
--RAISE WARNING 'public.process_logbook_queue_fn() scheduler vessel.id %, user.id', current_setting('vessel.id', false), current_setting('user.id', false);
|
||||
|
||||
-- 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);
|
||||
@@ -240,7 +240,7 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
|
||||
SET status = 'moored'
|
||||
WHERE time >= logbook_rec._from_time::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND time <= logbook_rec._to_time::TIMESTAMP WITHOUT TIME ZONE
|
||||
AND client_id = current_setting('vessel.client_id', false);
|
||||
AND vessel_id = current_setting('vessel.id', false);
|
||||
-- Update logbook
|
||||
UPDATE api.logbook
|
||||
SET notes = 'invalid logbook data, stationary need to fix metrics?'
|
||||
@@ -248,17 +248,17 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
|
||||
-- Get related stays
|
||||
SELECT id,departed,active INTO current_stays_id,current_stays_departed,current_stays_active
|
||||
FROM api.stays s
|
||||
WHERE s.client_id = current_setting('vessel.client_id', false)
|
||||
WHERE s.vessel_id = current_setting('vessel.id', false)
|
||||
AND s.arrived = logbook_rec._to_time;
|
||||
-- Update related stays
|
||||
UPDATE api.stays
|
||||
SET notes = 'invalid stays data, stationary need to fix metrics?'
|
||||
WHERE client_id = current_setting('vessel.client_id', false)
|
||||
WHERE vessel_id = current_setting('vessel.id', false)
|
||||
AND arrived = logbook_rec._to_time;
|
||||
-- Find previous stays
|
||||
SELECT id INTO previous_stays_id
|
||||
FROM api.stays s
|
||||
WHERE s.client_id = current_setting('vessel.client_id', false)
|
||||
WHERE s.vessel_id = current_setting('vessel.id', false)
|
||||
AND s.arrived < logbook_rec._to_time
|
||||
ORDER BY s.arrived DESC LIMIT 1;
|
||||
-- Update previous stays with the departed time from current stays
|
||||
@@ -266,7 +266,7 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
|
||||
UPDATE api.stays
|
||||
SET departed = current_stays_departed::timestamp without time zone,
|
||||
active = current_stays_active
|
||||
WHERE client_id = current_setting('vessel.client_id', false)
|
||||
WHERE vessel_id = current_setting('vessel.id', false)
|
||||
AND id = previous_stays_id;
|
||||
-- Clean u, remove invalid logbook and stay entry
|
||||
DELETE FROM api.logbook WHERE id = logbook_rec.id;
|
||||
@@ -307,12 +307,17 @@ CREATE OR REPLACE FUNCTION process_logbook_queue_fn(IN _id integer) RETURNS void
|
||||
|
||||
-- Prepare notification, gather user settings
|
||||
SELECT json_build_object('logbook_name', log_name, 'logbook_link', logbook_rec.id) into log_settings;
|
||||
user_settings := get_user_settings_from_clientid_fn(logbook_rec.client_id::TEXT);
|
||||
user_settings := get_user_settings_from_vesselid_fn(logbook_rec.vessel_id::TEXT);
|
||||
SELECT user_settings::JSONB || log_settings::JSONB into user_settings;
|
||||
RAISE DEBUG '-> debug process_logbook_queue_fn get_user_settings_from_clientid_fn [%]', user_settings;
|
||||
RAISE DEBUG '-> debug process_logbook_queue_fn get_user_settings_from_vesselid_fn [%]', user_settings;
|
||||
RAISE DEBUG '-> debug process_logbook_queue_fn log_settings [%]', log_settings;
|
||||
-- Send notification
|
||||
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;
|
||||
$process_logbook_queue$ LANGUAGE plpgsql;
|
||||
-- Description
|
||||
@@ -340,12 +345,12 @@ CREATE OR REPLACE FUNCTION process_stay_queue_fn(IN _id integer) RETURNS void AS
|
||||
AND longitude IS NOT NULL
|
||||
AND latitude IS NOT NULL;
|
||||
-- Ensure the query is successful
|
||||
IF stay_rec.client_id IS NULL THEN
|
||||
IF stay_rec.vessel_id IS NULL THEN
|
||||
RAISE WARNING '-> process_stay_queue_fn invalid stay %', _id;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
PERFORM set_config('vessel.client_id', stay_rec.client_id, false);
|
||||
PERFORM set_config('vessel.id', stay_rec.vessel_id, false);
|
||||
-- geo reverse _lng _lat
|
||||
_name := reverse_geocode_py_fn('nominatim', stay_rec.longitude::NUMERIC, stay_rec.latitude::NUMERIC);
|
||||
|
||||
@@ -372,6 +377,7 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
|
||||
DECLARE
|
||||
stay_rec record;
|
||||
moorage_rec record;
|
||||
user_settings jsonb;
|
||||
BEGIN
|
||||
RAISE NOTICE 'process_moorage_queue_fn';
|
||||
-- If _id is not NULL
|
||||
@@ -389,11 +395,13 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
|
||||
AND latitude IS NOT NULL
|
||||
AND id = _id;
|
||||
-- Ensure the query is successful
|
||||
IF stay_rec.client_id IS NULL THEN
|
||||
IF stay_rec.vessel_id IS NULL THEN
|
||||
RAISE WARNING '-> process_moorage_queue_fn invalid stay %', _id;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
PERFORM set_config('vessel.id', stay_rec.vessel_id, false);
|
||||
|
||||
-- Do we have an existing stay within 100m of the new moorage
|
||||
FOR moorage_rec in
|
||||
SELECT
|
||||
@@ -438,9 +446,9 @@ CREATE OR REPLACE FUNCTION process_moorage_queue_fn(IN _id integer) RETURNS void
|
||||
END IF;
|
||||
-- Insert new moorage from stay
|
||||
INSERT INTO api.moorages
|
||||
(client_id, name, stay_id, stay_code, stay_duration, reference_count, latitude, longitude, geog)
|
||||
(vessel_id, name, stay_id, stay_code, stay_duration, reference_count, latitude, longitude, geog)
|
||||
VALUES (
|
||||
stay_rec.client_id,
|
||||
stay_rec.vessel_id,
|
||||
stay_rec.name,
|
||||
stay_rec.id,
|
||||
stay_rec.stay_code,
|
||||
@@ -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))
|
||||
);
|
||||
END IF;
|
||||
|
||||
-- Process badges
|
||||
PERFORM badges_moorages_fn();
|
||||
END;
|
||||
$process_moorage_queue$ LANGUAGE plpgsql;
|
||||
-- Description
|
||||
@@ -560,7 +571,7 @@ AS $process_notification_queue$
|
||||
RETURN;
|
||||
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
|
||||
PERFORM set_config('user.email', account_rec.email, false);
|
||||
-- Generate user_settings user settings
|
||||
@@ -616,7 +627,7 @@ CREATE OR REPLACE FUNCTION process_vessel_queue_fn(IN _email TEXT) RETURNS void
|
||||
PERFORM set_config('user.email', vessel_rec.owner_email, false);
|
||||
-- Gather user settings
|
||||
user_settings := '{"email": "' || vessel_rec.owner_email || '", "boat": "' || vessel_rec.name || '"}';
|
||||
--user_settings := get_user_settings_from_clientid_fn();
|
||||
--user_settings := get_user_settings_from_vesselid_fn();
|
||||
-- Send notification email, pushover
|
||||
--PERFORM send_notification_fn('vessel'::TEXT, vessel_rec::RECORD);
|
||||
PERFORM send_email_py_fn('new_vessel'::TEXT, user_settings::JSONB, app_settings::JSONB);
|
||||
@@ -701,12 +712,12 @@ AS $send_notification$
|
||||
END IF;
|
||||
|
||||
-- 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
|
||||
WHERE a.email = user_settings->>'email'::TEXT;
|
||||
RAISE NOTICE '--> send_notification_fn telegram_notifications [%]', _telegram_notifications;
|
||||
-- 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 user_settings::JSONB || telegram_settings::JSONB into user_settings;
|
||||
--RAISE NOTICE '--> send_notification_fn user_settings + telegram [%]', user_settings;
|
||||
@@ -719,17 +730,17 @@ COMMENT ON FUNCTION
|
||||
public.send_notification_fn
|
||||
IS 'Send notifications via email, pushover, telegram to user base on user preferences';
|
||||
|
||||
DROP FUNCTION IF EXISTS get_user_settings_from_clientid_fn;
|
||||
CREATE OR REPLACE FUNCTION get_user_settings_from_clientid_fn(
|
||||
IN clientid TEXT,
|
||||
DROP FUNCTION IF EXISTS get_user_settings_from_vesselid_fn;
|
||||
CREATE OR REPLACE FUNCTION get_user_settings_from_vesselid_fn(
|
||||
IN vesselid TEXT,
|
||||
OUT user_settings JSONB
|
||||
) RETURNS JSONB
|
||||
AS $get_user_settings_from_clientid$
|
||||
AS $get_user_settings_from_vesselid$
|
||||
DECLARE
|
||||
BEGIN
|
||||
-- If client_id is not NULL
|
||||
IF clientid IS NULL OR clientid = '' THEN
|
||||
RAISE WARNING '-> get_user_settings_from_clientid_fn invalid input %', clientid;
|
||||
-- If vessel_id is not NULL
|
||||
IF vesselid IS NULL OR vesselid = '' THEN
|
||||
RAISE WARNING '-> get_user_settings_from_vesselid_fn invalid input %', vesselid;
|
||||
END IF;
|
||||
SELECT
|
||||
json_build_object(
|
||||
@@ -737,91 +748,325 @@ AS $get_user_settings_from_clientid$
|
||||
'recipient', a.first,
|
||||
'email', v.owner_email,
|
||||
'settings', a.preferences,
|
||||
'pushover_key', a.preferences->'pushover_key',
|
||||
'badges', a.preferences->'badges'
|
||||
'pushover_key', a.preferences->'pushover_key'
|
||||
--'badges', a.preferences->'badges'
|
||||
) INTO user_settings
|
||||
FROM auth.accounts a, auth.vessels v, api.metadata m
|
||||
WHERE m.mmsi = v.mmsi
|
||||
AND m.client_id = clientid
|
||||
WHERE m.vessel_id = v.vessel_id
|
||||
AND m.vessel_id = vesselid
|
||||
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;
|
||||
$get_user_settings_from_clientid$ LANGUAGE plpgsql;
|
||||
$get_user_settings_from_vesselid$ LANGUAGE plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.get_user_settings_from_clientid_fn
|
||||
IS 'get user settings details from a clientid, initiate for notifications';
|
||||
public.get_user_settings_from_vesselid_fn
|
||||
IS 'get user settings details from a vesselid initiate for notifications';
|
||||
|
||||
DROP FUNCTION IF EXISTS set_vessel_settings_from_clientid_fn;
|
||||
CREATE OR REPLACE FUNCTION set_vessel_settings_from_clientid_fn(
|
||||
IN clientid TEXT,
|
||||
DROP FUNCTION IF EXISTS set_vessel_settings_from_vesselid_fn;
|
||||
CREATE OR REPLACE FUNCTION set_vessel_settings_from_vesselid_fn(
|
||||
IN vesselid TEXT,
|
||||
OUT vessel_settings JSONB
|
||||
) RETURNS JSONB
|
||||
AS $set_vessel_settings_from_clientid$
|
||||
AS $set_vessel_settings_from_vesselid$
|
||||
DECLARE
|
||||
BEGIN
|
||||
-- If client_id is not NULL
|
||||
IF clientid IS NULL OR clientid = '' THEN
|
||||
RAISE WARNING '-> set_vessel_settings_from_clientid_fn invalid input %', clientid;
|
||||
-- If vessel_id is not NULL
|
||||
IF vesselid IS NULL OR vesselid = '' THEN
|
||||
RAISE WARNING '-> set_vessel_settings_from_vesselid_fn invalid input %', vesselid;
|
||||
END IF;
|
||||
SELECT
|
||||
json_build_object(
|
||||
'name' , v.name,
|
||||
'mmsi', v.mmsi,
|
||||
'vessel_id', v.vesselid,
|
||||
'client_id', m.client_id
|
||||
) INTO vessel_settings
|
||||
FROM auth.accounts a, auth.vessels v, api.metadata m
|
||||
WHERE m.mmsi = v.mmsi
|
||||
AND m.client_id = clientid;
|
||||
PERFORM set_config('vessel.mmsi', vessel_rec.mmsi, false);
|
||||
PERFORM set_config('vessel.name', vessel_rec.name, false);
|
||||
PERFORM set_config('vessel.client_id', vessel_rec.client_id, false);
|
||||
WHERE m.vessel_id = v.vessel_id
|
||||
AND m.vessel_id = vesselid;
|
||||
PERFORM set_config('vessel.name', vessel_settings->>'name'::TEXT, false);
|
||||
PERFORM set_config('vessel.client_id', vessel_settings->>'client_id'::TEXT, false);
|
||||
PERFORM set_config('vessel.id', vessel_settings->>'vessel_id'::TEXT, false);
|
||||
END;
|
||||
$set_vessel_settings_from_clientid$ LANGUAGE plpgsql;
|
||||
$set_vessel_settings_from_vesselid$ LANGUAGE plpgsql;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.set_vessel_settings_from_clientid_fn
|
||||
IS 'set_vessel settings details from a clientid, initiate for process queue functions';
|
||||
public.set_vessel_settings_from_vesselid_fn
|
||||
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
|
||||
badge_rec record;
|
||||
badges_arr record;
|
||||
begin
|
||||
SELECT json_array_elements_text((a.preferences->'badges')::json) from auth.accounts a;
|
||||
FOR badge_rec in
|
||||
SELECT
|
||||
name
|
||||
FROM badges
|
||||
LOOP
|
||||
-- found previous stay within 100m of the new moorage
|
||||
IF moorage_rec.id IS NOT NULL AND moorage_rec.id > 0 THEN
|
||||
RAISE NOTICE 'Found previous stay within 100m of moorage %', moorage_rec;
|
||||
EXIT; -- exit loop
|
||||
END IF;
|
||||
END LOOP;
|
||||
-- Helmsman
|
||||
-- select count(l.id) api.logbook l where count(l.id) = 1;
|
||||
-- Wake Maker
|
||||
-- select max(l.max_wind_speed) api.logbook l where l.max_wind_speed >= 15;
|
||||
-- Explorer
|
||||
-- select sum(m.stay_duration) api.stays s where home_flag is false;
|
||||
-- Mooring Pro
|
||||
-- select sum(m.stay_duration) api.stays s where stay_code = 3;
|
||||
-- Anchormaster
|
||||
-- select sum(m.stay_duration) api.stays s where stay_code = 2;
|
||||
-- Traveler
|
||||
-- todo country to country.
|
||||
-- Stormtrooper
|
||||
-- select max(l.max_wind_speed) api.logbook l where l.max_wind_speed >= 30;
|
||||
-- Club Alaska
|
||||
-- todo country zone
|
||||
-- Tropical Traveler
|
||||
-- todo country zone
|
||||
-- Aloha Award
|
||||
-- todo pacific zone
|
||||
-- TODO the sea is big and the world is not limited to the US
|
||||
END
|
||||
$process_badge_queue$ language plpgsql;
|
||||
---------------------------------------------------------------------------
|
||||
-- Badges
|
||||
--
|
||||
CREATE OR REPLACE FUNCTION public.badges_logbook_fn(IN logbook_id integer) RETURNS VOID AS $badges_logbook$
|
||||
DECLARE
|
||||
_badges jsonb;
|
||||
_exist BOOLEAN := null;
|
||||
total integer;
|
||||
max_wind_speed integer;
|
||||
distance integer;
|
||||
badge text;
|
||||
user_settings jsonb;
|
||||
BEGIN
|
||||
|
||||
-- Helmsman = first log entry
|
||||
SELECT (preferences->'badges'->'Helmsman') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
|
||||
if _exist is false THEN
|
||||
-- is first logbook?
|
||||
select count(*) into total from api.logbook l where vessel_id = current_setting('vessel.id', false);
|
||||
if total >= 1 then
|
||||
-- Add badge
|
||||
badge := '{"Helmsman": {"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
|
||||
PERFORM api.update_user_preferences_fn('{badges}'::TEXT, badge::TEXT);
|
||||
-- Gather user settings
|
||||
user_settings := get_user_settings_from_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Helmsman"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_badge'::TEXT, user_settings::JSONB);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Wake Maker = windspeeds above 15kts
|
||||
SELECT (preferences->'badges'->'Wake Maker') IS NOT NULL INTO _exist FROM auth.accounts a WHERE a.email = current_setting('user.email', false);
|
||||
--RAISE WARNING '-> Wake Maker %', _exist;
|
||||
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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Wake Maker"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Stormtrooper"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Navigator Award"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Captain Award"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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_vesselid_fn(current_setting('vessel.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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Explorer"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Mooring Pro"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || '{"badge": "Anchormaster"}'::JSONB into user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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.id [%]', current_setting('user.email', false), current_setting('vessel.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 vessel_id = current_setting('vessel.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_vesselid_fn(current_setting('vessel.id', false));
|
||||
SELECT user_settings::JSONB || badge_tmp::JSONB INTO user_settings;
|
||||
-- Send notification
|
||||
PERFORM send_notification_fn('new_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
|
||||
@@ -836,7 +1081,6 @@ DECLARE
|
||||
_email text;
|
||||
_mmsi name;
|
||||
_path name;
|
||||
_clientid text;
|
||||
_vid text;
|
||||
account_rec record;
|
||||
vessel_rec record;
|
||||
@@ -849,6 +1093,11 @@ BEGIN
|
||||
--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 '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
|
||||
-- Check the user exist in the accounts table
|
||||
SELECT * INTO account_rec
|
||||
@@ -892,19 +1141,10 @@ BEGIN
|
||||
-- Set session variables
|
||||
PERFORM set_config('vessel.id', vessel_rec.vessel_id, false);
|
||||
PERFORM set_config('vessel.name', vessel_rec.name, false);
|
||||
-- ensure vessel is connected
|
||||
SELECT coalesce(m.client_id, null) INTO _clientid
|
||||
FROM auth.vessels v, api.metadata m
|
||||
WHERE
|
||||
m.vessel_id = current_setting('vessel.id')
|
||||
AND m.vessel_id = v.vessel_id
|
||||
AND v.owner_email =_email;
|
||||
-- Set session variables
|
||||
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.id [%]', current_setting('vessel.id', false);
|
||||
--RAISE WARNING 'public.check_jwt() user_role vessel.name [%]', current_setting('vessel.name', false);
|
||||
ELSIF _role = 'vessel_role' THEN
|
||||
-- Extract vessel_id from jwt token
|
||||
SELECT current_setting('request.jwt.claims', true)::json->>'vid' INTO _vid;
|
||||
-- Check the vessel and user exist
|
||||
SELECT auth.vessels.* INTO vessel_rec
|
||||
@@ -918,11 +1158,8 @@ BEGIN
|
||||
END IF;
|
||||
PERFORM set_config('vessel.id', vessel_rec.vessel_id, false);
|
||||
PERFORM set_config('vessel.name', vessel_rec.name, false);
|
||||
-- TODO add client_id
|
||||
--PERFORM set_config('vessel.client_id', vessel_rec.client_id, false);
|
||||
--RAISE WARNING 'public.check_jwt() user_role vessel.mmsi %', current_setting('vessel.mmsi', false);
|
||||
--RAISE WARNING 'public.check_jwt() user_role vessel.name %', current_setting('vessel.name', 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.id %', current_setting('vessel.id', false);
|
||||
ELSIF _role <> 'api_anonymous' THEN
|
||||
RAISE EXCEPTION 'Invalid role'
|
||||
USING HINT = 'Stop being so evil and maybe you can log in';
|
||||
@@ -945,3 +1182,23 @@ BEGIN
|
||||
perform public.cron_process_monitor_offline_fn();
|
||||
END
|
||||
$$ language plpgsql security definer;
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
-- Delete all data for a account by email and vessel_id
|
||||
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;
|
||||
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;
|
||||
delete from api.moorages m 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;
|
||||
delete from auth.vessels v where vessel_id = _vessel_id;
|
||||
select * from auth.accounts a where email = _email;
|
||||
delete from auth.accounts a where email = _email;
|
||||
RETURN True;
|
||||
END
|
||||
$delete_account$ language plpgsql security definer;
|
||||
|
@@ -345,10 +345,10 @@ $urlencode_py$ LANGUAGE plpython3u IMMUTABLE STRICT;
|
||||
-- python
|
||||
-- https://ipapi.co/
|
||||
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$
|
||||
"""
|
||||
TODO
|
||||
Return ipapi.co ip details
|
||||
"""
|
||||
import requests
|
||||
import json
|
||||
@@ -358,13 +358,15 @@ AS $reverse_geoip_py$
|
||||
r = requests.get(url)
|
||||
#print(r.text)
|
||||
# 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:
|
||||
plpy.notice('Sent successfully to [{}] [{}]'.format(r.text, r.status_code))
|
||||
#plpy.notice('Got [{}] [{}]'.format(r.text, r.status_code))
|
||||
return r.text;
|
||||
else:
|
||||
plpy.error('Failed to send')
|
||||
return None
|
||||
$reverse_geoip_py$ TRANSFORM FOR TYPE jsonb LANGUAGE plpython3u;
|
||||
plpy.error('Failed to get ip details')
|
||||
return '{}'
|
||||
$reverse_geoip_py$ LANGUAGE plpython3u;
|
||||
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
public.reverse_geoip_py_fn
|
||||
@@ -403,6 +405,8 @@ AS $geojson_py$
|
||||
#plpy.notice(feature)
|
||||
if (feature['geometry']['type'] != geometry_type):
|
||||
output.append(feature)
|
||||
#elif (feature['properties']['id']): TODO
|
||||
# output.append(feature)
|
||||
#else:
|
||||
# plpy.notice('ignoring')
|
||||
return json.dumps(output)
|
||||
|
@@ -58,7 +58,7 @@ COMMENT ON TRIGGER accounts_moddatetime
|
||||
DROP TABLE IF EXISTS auth.vessels;
|
||||
CREATE TABLE IF NOT EXISTS auth.vessels (
|
||||
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,
|
||||
-- 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
|
||||
@@ -73,7 +73,7 @@ CREATE TABLE IF NOT EXISTS auth.vessels (
|
||||
-- Description
|
||||
COMMENT ON TABLE
|
||||
auth.vessels
|
||||
IS 'vessels table link to accounts email column';
|
||||
IS 'vessels table link to accounts email user_id column';
|
||||
-- Indexes
|
||||
CREATE INDEX vessels_role_idx ON auth.vessels (role);
|
||||
CREATE INDEX vessels_name_idx ON auth.vessels (name);
|
||||
@@ -174,6 +174,7 @@ declare
|
||||
app_jwt_secret text;
|
||||
_email_valid boolean := false;
|
||||
_email text := email;
|
||||
_user_id text := null;
|
||||
begin
|
||||
-- check email and password
|
||||
select auth.user_role(email, pass) into _role;
|
||||
@@ -187,14 +188,15 @@ begin
|
||||
WHERE name = 'app.jwt_secret';
|
||||
|
||||
-- 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
|
||||
WHERE a.email = _email;
|
||||
IF _email_valid is null or _email_valid is False THEN
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('email_otp', email, now());
|
||||
INSERT INTO process_queue (channel, payload, stored, ref_id)
|
||||
VALUES ('email_otp', email, now(), _user_id);
|
||||
END IF;
|
||||
|
||||
--RAISE WARNING 'api.login debug: [%],[%],[%]', app_jwt_secret, _role, login.email;
|
||||
-- Generate jwt
|
||||
select jwt.sign(
|
||||
-- row_to_json(r), ''
|
||||
@@ -202,7 +204,8 @@ begin
|
||||
row_to_json(r)::json, app_jwt_secret
|
||||
) as token
|
||||
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, -- add support in check_jwt
|
||||
extract(epoch from now())::integer + 60*60 as exp
|
||||
) r
|
||||
into result;
|
||||
@@ -275,7 +278,8 @@ begin
|
||||
) as token
|
||||
from (
|
||||
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
|
||||
) r
|
||||
into result;
|
||||
|
@@ -9,9 +9,19 @@ select current_database();
|
||||
\c signalk
|
||||
|
||||
-- Link auth.vessels with api.metadata
|
||||
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;
|
||||
ALTER TABLE api.metadata ADD FOREIGN KEY (vessel_id) REFERENCES auth.vessels(vessel_id) ON DELETE RESTRICT;
|
||||
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
|
||||
--TODO add geojson with position
|
||||
DROP VIEW IF EXISTS api.vessels_view;
|
||||
@@ -60,42 +70,37 @@ COMMENT ON FUNCTION
|
||||
DROP FUNCTION IF EXISTS api.vessel_fn;
|
||||
CREATE OR REPLACE FUNCTION api.vessel_fn(OUT vessel JSON) RETURNS JSON
|
||||
AS $vessel$
|
||||
DECLARE
|
||||
DECLARE
|
||||
BEGIN
|
||||
SELECT
|
||||
json_build_object(
|
||||
'name', v.name,
|
||||
'mmsi', coalesce(v.mmsi, null),
|
||||
'created_at', v.created_at::timestamp(0),
|
||||
'last_contact', coalesce(m.time, null),
|
||||
'geojson', coalesce(ST_AsGeoJSON(geojson_t.*)::json, null)
|
||||
)
|
||||
jsonb_build_object(
|
||||
'name', v.name,
|
||||
'mmsi', coalesce(v.mmsi, null),
|
||||
'created_at', v.created_at::timestamp(0),
|
||||
'last_contact', coalesce(m.time, null),
|
||||
'geojson', coalesce(ST_AsGeoJSON(geojson_t.*)::json, null)
|
||||
)::jsonb || api.vessel_details_fn()::jsonb
|
||||
INTO vessel
|
||||
FROM auth.vessels v, api.metadata m,
|
||||
( SELECT
|
||||
t.*
|
||||
FROM (
|
||||
( select
|
||||
current_setting('vessel.name') as name,
|
||||
time,
|
||||
courseovergroundtrue,
|
||||
speedoverground,
|
||||
anglespeedapparent,
|
||||
longitude,latitude,
|
||||
st_makepoint(longitude,latitude) AS geo_point
|
||||
FROM api.metrics
|
||||
WHERE
|
||||
latitude IS NOT NULL
|
||||
AND longitude IS NOT NULL
|
||||
AND client_id = current_setting('vessel.client_id', false)
|
||||
ORDER BY time DESC
|
||||
)
|
||||
) AS t
|
||||
) AS geojson_t
|
||||
( select
|
||||
current_setting('vessel.name') as name,
|
||||
time,
|
||||
courseovergroundtrue,
|
||||
speedoverground,
|
||||
anglespeedapparent,
|
||||
longitude,latitude,
|
||||
st_makepoint(longitude,latitude) AS geo_point
|
||||
FROM api.metrics
|
||||
WHERE
|
||||
latitude IS NOT NULL
|
||||
AND longitude IS NOT NULL
|
||||
AND vessel_id = current_setting('vessel.id', false)
|
||||
ORDER BY time DESC
|
||||
) AS geojson_t
|
||||
WHERE
|
||||
m.vessel_id = current_setting('vessel.id')
|
||||
AND m.vessel_id = v.vessel_id;
|
||||
--RAISE notice 'api.vessel_fn %', obj;
|
||||
--RAISE notice 'api.vessel_fn %', obj;
|
||||
END;
|
||||
$vessel$ language plpgsql security definer;
|
||||
-- Description
|
||||
@@ -126,16 +131,18 @@ COMMENT ON FUNCTION
|
||||
DROP FUNCTION IF EXISTS api.versions_fn;
|
||||
CREATE OR REPLACE FUNCTION api.versions_fn() RETURNS JSON
|
||||
AS $version$
|
||||
DECLARE
|
||||
_appv TEXT;
|
||||
_sysv TEXT;
|
||||
DECLARE
|
||||
_appv TEXT;
|
||||
_sysv TEXT;
|
||||
BEGIN
|
||||
SELECT
|
||||
value, rtrim(substring(version(), 0, 17)) AS sys_version into _appv,_sysv
|
||||
FROM app_settings
|
||||
WHERE name = 'app.version';
|
||||
FROM app_settings
|
||||
WHERE name = 'app.version';
|
||||
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;
|
||||
$version$ language plpgsql security definer;
|
||||
-- Description
|
||||
@@ -193,3 +200,27 @@ $update_user_preferences$ language plpgsql security definer;
|
||||
COMMENT ON FUNCTION
|
||||
api.update_user_preferences_fn
|
||||
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 vessel_id = current_setting('vessel.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';
|
||||
|
@@ -83,7 +83,7 @@ AS $recover_fn$
|
||||
DECLARE
|
||||
_email CITEXT := email;
|
||||
_user_id TEXT := NULL;
|
||||
otp_pass VARCHAR(10) := NULL;
|
||||
otp_pass TEXT := NULL;
|
||||
_reset_qs TEXT := NULL;
|
||||
user_settings jsonb := NULL;
|
||||
BEGIN
|
||||
@@ -96,9 +96,8 @@ AS $recover_fn$
|
||||
RAISE EXCEPTION 'Invalid input'
|
||||
USING HINT = 'Check your parameter';
|
||||
END IF;
|
||||
-- OTP Code
|
||||
SELECT generate_uid_fn(6) INTO otp_pass;
|
||||
INSERT INTO auth.otp (user_email, otp_pass) VALUES (_email, otp_pass);
|
||||
-- Generate OTP
|
||||
otp_pass := api.generate_otp_fn(email);
|
||||
SELECT CONCAT('uuid=', _user_id, '&token=', otp_pass) INTO _reset_qs;
|
||||
-- Send email/notifications
|
||||
user_settings := '{"email": "' || _email || '", "reset_qs": "' || _reset_qs || '"}';
|
||||
@@ -232,7 +231,7 @@ AS $email_validation$
|
||||
-- Send Notification async
|
||||
--INSERT INTO process_queue (channel, payload, stored)
|
||||
-- VALUES ('email_valid', _email, now());
|
||||
RETURN True;
|
||||
RETURN True;
|
||||
END IF;
|
||||
RETURN False;
|
||||
END;
|
||||
@@ -276,7 +275,7 @@ AS $pushover_subscribe_link$
|
||||
name = 'app.pushover_app_url';
|
||||
-- Generate OTP
|
||||
otp_code := api.generate_otp_fn(email);
|
||||
-- On sucess redirect to API endpoint
|
||||
-- On success redirect to API endpoint
|
||||
SELECT CONCAT(
|
||||
'?success=',
|
||||
public.urlescape_py_fn(CONCAT(app_url,'/pushover?token=')),
|
||||
@@ -322,7 +321,7 @@ AS $pushover$
|
||||
DELETE FROM auth.otp
|
||||
WHERE user_email = _email;
|
||||
-- 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
|
||||
--INSERT INTO process_queue (channel, payload, stored)
|
||||
@@ -335,16 +334,15 @@ $pushover$ language plpgsql security definer;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
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
|
||||
-- Expose as an API endpoint
|
||||
DROP FUNCTION IF EXISTS api.telegram_fn;
|
||||
CREATE OR REPLACE FUNCTION api.telegram_fn(IN token TEXT, IN telegram_obj TEXT) RETURNS BOOLEAN
|
||||
AS $telegram$
|
||||
DECLARE
|
||||
_email TEXT := NULL;
|
||||
_updated BOOLEAN := False;
|
||||
DECLARE
|
||||
_email TEXT := NULL;
|
||||
user_settings jsonb;
|
||||
BEGIN
|
||||
-- Check parameters
|
||||
@@ -357,14 +355,14 @@ AS $telegram$
|
||||
-- Set user email into env to allow RLS update
|
||||
PERFORM set_config('user.email', _email, false);
|
||||
-- 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 FROM auth.otp
|
||||
WHERE user_email = _email;
|
||||
-- Send Notification async
|
||||
INSERT INTO process_queue (channel, payload, stored)
|
||||
VALUES ('telegram_valid', _email, now());
|
||||
RETURN _updated;
|
||||
--INSERT INTO process_queue (channel, payload, stored)
|
||||
-- VALUES ('telegram_valid', _email, now());
|
||||
RETURN True;
|
||||
END IF;
|
||||
RETURN False;
|
||||
END;
|
||||
@@ -372,15 +370,15 @@ $telegram$ language plpgsql security definer;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
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
|
||||
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
|
||||
AS $telegram_user_exists$
|
||||
DECLARE
|
||||
_email CITEXT := email;
|
||||
_user_id BIGINT := user_id;
|
||||
DECLARE
|
||||
_email CITEXT := email;
|
||||
_user_id BIGINT := user_id;
|
||||
BEGIN
|
||||
IF _email IS NULL OR _chat_id IS NULL THEN
|
||||
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
|
||||
FROM auth.accounts a
|
||||
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
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
@@ -399,22 +397,22 @@ $telegram_user_exists$ language plpgsql security definer;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
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
|
||||
DROP FUNCTION IF EXISTS auth.telegram_otp_fn;
|
||||
CREATE OR REPLACE FUNCTION auth.telegram_otp_fn(IN email TEXT, OUT otp_code TEXT) RETURNS TEXT
|
||||
DROP FUNCTION IF EXISTS api.telegram_otp_fn;
|
||||
CREATE OR REPLACE FUNCTION api.telegram_otp_fn(IN email TEXT, OUT otp_code TEXT) RETURNS TEXT
|
||||
AS $telegram_otp$
|
||||
DECLARE
|
||||
_email CITEXT := email;
|
||||
user_settings jsonb := NULL;
|
||||
DECLARE
|
||||
_email CITEXT := email;
|
||||
user_settings jsonb := NULL;
|
||||
BEGIN
|
||||
IF _email IS NULL THEN
|
||||
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
|
||||
END IF;
|
||||
-- Generate token
|
||||
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
|
||||
PERFORM set_config('user.email', _email, false);
|
||||
-- Send Notification
|
||||
@@ -425,30 +423,38 @@ AS $telegram_otp$
|
||||
$telegram_otp$ language plpgsql security definer;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
auth.telegram_otp_fn
|
||||
IS 'TODO';
|
||||
api.telegram_otp_fn
|
||||
IS 'Telegram otp generation';
|
||||
|
||||
-- Telegram bot JWT auth
|
||||
-- Telegram JWT auth
|
||||
-- Expose as an API endpoint
|
||||
-- Avoid sending a password so use email and chat_id as key pair
|
||||
DROP FUNCTION IF EXISTS api.bot(text,BIGINT);
|
||||
CREATE OR REPLACE FUNCTION api.bot(IN email TEXT, IN user_id BIGINT) RETURNS auth.jwt_token
|
||||
AS $telegram_bot$
|
||||
DECLARE
|
||||
_email TEXT := email;
|
||||
_user_id BIGINT := user_id;
|
||||
DROP FUNCTION IF EXISTS api.telegram;
|
||||
CREATE OR REPLACE FUNCTION api.telegram(IN user_id BIGINT, IN email TEXT DEFAULT NULL) RETURNS auth.jwt_token
|
||||
AS $telegram_jwt$
|
||||
DECLARE
|
||||
_email TEXT := email;
|
||||
_user_id BIGINT := user_id;
|
||||
_uid TEXT := NULL;
|
||||
_exist BOOLEAN := False;
|
||||
result auth.jwt_token;
|
||||
app_jwt_secret text;
|
||||
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';
|
||||
END IF;
|
||||
-- check email and _chat_id
|
||||
select auth.telegram_user_exists_fn(_email, _user_id) into _exist;
|
||||
if _exist is null or _exist <> True then
|
||||
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
|
||||
end if;
|
||||
|
||||
-- Check _user_id
|
||||
SELECT auth.telegram_session_exists_fn(_user_id) into _exist;
|
||||
IF _exist IS NULL OR _exist <> True THEN
|
||||
--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
|
||||
SELECT value INTO app_jwt_secret
|
||||
@@ -460,28 +466,30 @@ AS $telegram_bot$
|
||||
row_to_json(r)::json, app_jwt_secret
|
||||
) as token
|
||||
from (
|
||||
select 'user_role' as role,
|
||||
(select lower(_email)) as email,
|
||||
select 'user_role' as role,
|
||||
(select lower(_email)) as email,
|
||||
_uid as uid,
|
||||
extract(epoch from now())::integer + 60*60 as exp
|
||||
) r
|
||||
into result;
|
||||
return result;
|
||||
END;
|
||||
$telegram_bot$ language plpgsql security definer;
|
||||
$telegram_jwt$ language plpgsql security definer;
|
||||
-- Description
|
||||
COMMENT ON FUNCTION
|
||||
api.bot
|
||||
IS 'Generate a JWT user_role token from email for telegram bot';
|
||||
api.telegram
|
||||
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;
|
||||
CREATE OR REPLACE FUNCTION auth.telegram_session_exists_fn(IN user_id BIGINT) RETURNS BOOLEAN
|
||||
AS $telegram_session_exists$
|
||||
DECLARE
|
||||
_id TEXT := NULL;
|
||||
_user_id BIGINT := user_id;
|
||||
DECLARE
|
||||
_id BIGINT := NULL;
|
||||
_user_id BIGINT := user_id;
|
||||
_email TEXT := NULL;
|
||||
BEGIN
|
||||
IF _chat_id IS NULL THEN
|
||||
IF user_id IS NULL THEN
|
||||
RAISE EXCEPTION 'invalid input' USING HINT = 'check your parameter';
|
||||
END IF;
|
||||
|
||||
@@ -489,10 +497,10 @@ AS $telegram_session_exists$
|
||||
SELECT preferences->'telegram'->'from'->'id' INTO _id
|
||||
FROM auth.accounts a
|
||||
WHERE cast(preferences->'telegram'->'from'->'id' as BIGINT) = _user_id::BIGINT;
|
||||
IF NOT FOUND then
|
||||
RETURN False;
|
||||
IF FOUND THEN
|
||||
RETURN True;
|
||||
END IF;
|
||||
RETURN True;
|
||||
RETURN FALSE;
|
||||
END;
|
||||
$telegram_session_exists$ language plpgsql security definer;
|
||||
-- Description
|
||||
|
@@ -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;
|
||||
-- explicitly limit EXECUTE privileges to pgrest db-pre-request function
|
||||
grant execute on function public.check_jwt() to api_anonymous;
|
||||
-- explicitly limit EXECUTE privileges to only telegram bot auth function
|
||||
grant execute on function api.bot(text,bigint) to api_anonymous;
|
||||
-- explicitly limit EXECUTE privileges to only telegram jwt auth function
|
||||
grant execute on function api.telegram(bigint,text) to api_anonymous;
|
||||
-- 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.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_otp_fn(text) to api_anonymous;
|
||||
--grant execute on function api.generate_otp_fn(text) to api_anonymous;
|
||||
|
||||
-- authenticator
|
||||
-- login role
|
||||
@@ -183,19 +185,19 @@ CREATE POLICY admin_all ON api.metadata TO current_user
|
||||
WITH CHECK (true);
|
||||
-- Allow vessel_role to insert and select on their own records
|
||||
CREATE POLICY api_vessel_role ON api.metadata TO vessel_role
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (true);
|
||||
-- Allow user_role to update and select on their own records
|
||||
CREATE POLICY api_user_role ON api.metadata TO user_role
|
||||
USING (client_id = current_setting('vessel.client_id', true))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow scheduler to update and select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', true))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow scheduler to update and select based on the vessel.id
|
||||
CREATE POLICY api_scheduler_role ON api.metadata TO scheduler
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow grafana to select based on email
|
||||
CREATE POLICY grafana_role ON api.metadata TO grafana
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (false);
|
||||
-- Allow grafana_auth to select
|
||||
CREATE POLICY grafana_proxy_role ON api.metadata TO grafana_auth
|
||||
@@ -209,19 +211,19 @@ CREATE POLICY admin_all ON api.metrics TO current_user
|
||||
WITH CHECK (true);
|
||||
-- Allow vessel_role to insert and select on their own records
|
||||
CREATE POLICY api_vessel_role ON api.metrics TO vessel_role
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (true);
|
||||
-- Allow user_role to update and select on their own records
|
||||
CREATE POLICY api_user_role ON api.metrics TO user_role
|
||||
USING (client_id = current_setting('vessel.client_id', true))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow scheduler to update and select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', true))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow scheduler to update and select based on the vessel.id
|
||||
CREATE POLICY api_scheduler_role ON api.metrics TO scheduler
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow grafana to select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow grafana to select based on the vessel.id
|
||||
CREATE POLICY grafana_role ON api.metrics TO grafana
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (false);
|
||||
|
||||
-- Be sure to enable row level security on the table
|
||||
@@ -233,19 +235,19 @@ CREATE POLICY admin_all ON api.logbook TO current_user
|
||||
WITH CHECK (true);
|
||||
-- Allow vessel_role to insert and select on their own records
|
||||
CREATE POLICY api_vessel_role ON api.logbook TO vessel_role
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (true);
|
||||
-- Allow user_role to update and select on their own records
|
||||
CREATE POLICY api_user_role ON api.logbook TO user_role
|
||||
USING (client_id = current_setting('vessel.client_id', true))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow scheduler to update and select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', true))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow scheduler to update and select based on the vessel.id
|
||||
CREATE POLICY api_scheduler_role ON api.logbook TO scheduler
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow grafana to select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow grafana to select based on the vessel.id
|
||||
CREATE POLICY grafana_role ON api.logbook TO grafana
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (false);
|
||||
|
||||
-- Be sure to enable row level security on the table
|
||||
@@ -256,19 +258,19 @@ CREATE POLICY admin_all ON api.stays TO current_user
|
||||
WITH CHECK (true);
|
||||
-- Allow vessel_role to insert and select on their own records
|
||||
CREATE POLICY api_vessel_role ON api.stays TO vessel_role
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (true);
|
||||
-- Allow user_role to update and select on their own records
|
||||
CREATE POLICY api_user_role ON api.stays TO user_role
|
||||
USING (client_id = current_setting('vessel.client_id', true))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow scheduler to update and select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', true))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow scheduler to update and select based on the vessel_id
|
||||
CREATE POLICY api_scheduler_role ON api.stays TO scheduler
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow grafana to select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow grafana to select based on the vessel_id
|
||||
CREATE POLICY grafana_role ON api.stays TO grafana
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (false);
|
||||
|
||||
-- Be sure to enable row level security on the table
|
||||
@@ -279,19 +281,19 @@ CREATE POLICY admin_all ON api.moorages TO current_user
|
||||
WITH CHECK (true);
|
||||
-- Allow vessel_role to insert and select on their own records
|
||||
CREATE POLICY api_vessel_role ON api.moorages TO vessel_role
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (true);
|
||||
-- Allow user_role to update and select on their own records
|
||||
CREATE POLICY api_user_role ON api.moorages TO user_role
|
||||
USING (client_id = current_setting('vessel.client_id', true))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow scheduler to update and select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', true))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow scheduler to update and select based on the vessel_id
|
||||
CREATE POLICY api_scheduler_role ON api.moorages TO scheduler
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
WITH CHECK (client_id = current_setting('vessel.client_id', false));
|
||||
-- Allow grafana to select based on the client_id
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (vessel_id = current_setting('vessel.id', false));
|
||||
-- Allow grafana to select based on the vessel_id
|
||||
CREATE POLICY grafana_role ON api.moorages TO grafana
|
||||
USING (client_id = current_setting('vessel.client_id', false))
|
||||
USING (vessel_id = current_setting('vessel.id', false))
|
||||
WITH CHECK (false);
|
||||
|
||||
-- Be sure to enable row level security on the table
|
||||
|
76
initdb/07naturalearthdata.sql
Normal file
76
initdb/07naturalearthdata.sql
Normal file
@@ -0,0 +1,76 @@
|
||||
---------------------------------------------------------------------------
|
||||
-- https://www.naturalearthdata.com
|
||||
--
|
||||
-- https://naciscdn.org/naturalearth/10m/physical/ne_10m_geography_marine_polys.zip
|
||||
--
|
||||
-- https://github.com/nvkelso/natural-earth-vector/raw/master/10m_physical/ne_10m_geography_marine_polys.shp
|
||||
--
|
||||
|
||||
-- Import from shapefile
|
||||
-- # shp2pgsql ne_10m_geography_marine_polys.shp public.ne_10m_geography_marine_polys | psql -U ${POSTGRES_USER} signalk
|
||||
--
|
||||
-- PostgSail Customization, add tropics and alaska area.
|
||||
|
||||
-- List current database
|
||||
select current_database();
|
||||
|
||||
-- connect to the DB
|
||||
\c signalk
|
||||
|
||||
CREATE TABLE public.ne_10m_geography_marine_polys (
|
||||
gid serial4 NOT NULL,
|
||||
featurecla TEXT NULL,
|
||||
"name" TEXT NULL,
|
||||
namealt TEXT NULL,
|
||||
changed TEXT NULL,
|
||||
note TEXT NULL,
|
||||
name_fr TEXT NULL,
|
||||
min_label float8 NULL,
|
||||
max_label float8 NULL,
|
||||
scalerank int2 NULL,
|
||||
"label" TEXT NULL,
|
||||
wikidataid TEXT NULL,
|
||||
name_ar TEXT NULL,
|
||||
name_bn TEXT NULL,
|
||||
name_de TEXT NULL,
|
||||
name_en TEXT NULL,
|
||||
name_es TEXT NULL,
|
||||
name_el TEXT NULL,
|
||||
name_hi TEXT NULL,
|
||||
name_hu TEXT NULL,
|
||||
name_id TEXT NULL,
|
||||
name_it TEXT NULL,
|
||||
name_ja TEXT NULL,
|
||||
name_ko TEXT NULL,
|
||||
name_nl TEXT NULL,
|
||||
name_pl TEXT NULL,
|
||||
name_pt TEXT NULL,
|
||||
name_ru TEXT NULL,
|
||||
name_sv TEXT NULL,
|
||||
name_tr TEXT NULL,
|
||||
name_vi TEXT NULL,
|
||||
name_zh TEXT NULL,
|
||||
ne_id int8 NULL,
|
||||
name_fa TEXT NULL,
|
||||
name_he TEXT NULL,
|
||||
name_uk TEXT NULL,
|
||||
name_ur TEXT NULL,
|
||||
name_zht TEXT NULL,
|
||||
geom geometry(multipolygon,4326) NULL,
|
||||
CONSTRAINT ne_10m_geography_marine_polys_pkey PRIMARY KEY (gid)
|
||||
);
|
||||
-- Add GIST index
|
||||
CREATE INDEX ne_10m_geography_marine_polys_geom_idx
|
||||
ON public.ne_10m_geography_marine_polys
|
||||
USING GIST (geom);
|
||||
|
||||
-- Description
|
||||
COMMENT ON TABLE
|
||||
public.ne_10m_geography_marine_polys
|
||||
IS 'imperfect but light weight geographic marine areas from https://www.naturalearthdata.com';
|
||||
|
||||
-- Import data
|
||||
COPY public.ne_10m_geography_marine_polys(gid,featurecla,"name",namealt,changed,note,name_fr,min_label,max_label,scalerank,"label",wikidataid,name_ar,name_bn,name_de,name_en,name_es,name_el,name_hi,name_hu,name_id,name_it,name_ja,name_ko,name_nl,name_pl,name_pt,name_ru,name_sv,name_tr,name_vi,name_zh,ne_id,name_fa,name_he,name_uk,name_ur,name_zht,geom)
|
||||
FROM '/docker-entrypoint-initdb.d/ne_10m_geography_marine_polys.csv'
|
||||
DELIMITER ','
|
||||
CSV HEADER;
|
@@ -1 +1 @@
|
||||
0.0.11
|
||||
0.2.1
|
||||
|
310
initdb/ne_10m_geography_marine_polys.csv
Normal file
310
initdb/ne_10m_geography_marine_polys.csv
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user