diff --git a/.env.example b/.env.example index 9ff4586..e16c7fa 100644 --- a/.env.example +++ b/.env.example @@ -48,7 +48,12 @@ ADMIN_EMAIL=admin@example.com # if you want to use a different database for the location data. # DB_LOCATION_TABLE=location_history -## Database mappings - mostly useful if you want to use a different database for the location data +### +### Location history table column mappings. +### The following settings are only taken into account when you use a different database +### for DB_LOCATION_URL than the one used by the backend (DB_URL). +### + # The name of the column that contains the primary key of each location point # DB_LOCATION__ID=id @@ -76,7 +81,8 @@ ADMIN_EMAIL=admin@example.com # Comment or leave empty if the locality is not available. # DB_LOCATION__LOCALITY=locality -# The name of the column that contains the country code of each location point +# The name of the column that contains the country code of each location point. +# The country code should be a two-letter ISO 3166-1 alpha-2 code. # Comment or leave empty if the country code is not available. # DB_LOCATION__COUNTRY=country @@ -88,6 +94,18 @@ ADMIN_EMAIL=admin@example.com # Comment or leave empty if the description is not available. # DB_LOCATION__DESCRIPTION=description +# The name of the column that contains the battery level of each location point +# Comment or leave empty if the battery level is not available. +# DB_LOCATION__BATTERY_LEVEL=battery + +# The name of the column that contains the accuracy of each location point, in meters +# Comment or leave empty if the accuracy is not available. +# DB_LOCATION__ACCURACY=accuracy + +# The name of the column that contains the speed of each location point +# Comment or leave empty if the speed is not available. +# DB_LOCATION__SPEED=speed + ### ### Frontend configuration. ### This is only required if you want to run the frontend in development mode diff --git a/frontend/src/models/GPSPoint.ts b/frontend/src/models/GPSPoint.ts index 14c68c3..4091a8d 100644 --- a/frontend/src/models/GPSPoint.ts +++ b/frontend/src/models/GPSPoint.ts @@ -9,6 +9,9 @@ class GPSPoint { public country: string; public postalCode: string; public description?: string; + public battery?: number; + public speed?: number; + public accuracy?: number; public timestamp: Date; constructor({ @@ -22,6 +25,9 @@ class GPSPoint { country, postalCode, description, + battery, + speed, + accuracy, timestamp, }: { id: number; @@ -34,6 +40,9 @@ class GPSPoint { country: string; postalCode: string; description?: string; + battery?: number; + speed?: number; + accuracy?: number; timestamp: Date; }) { this.id = id; @@ -46,6 +55,9 @@ class GPSPoint { this.country = country; this.postalCode = postalCode; this.description = description; + this.battery = battery; + this.speed = speed; + this.accuracy = accuracy; this.timestamp = timestamp; } } diff --git a/src/db/Db.ts b/src/db/Db.ts index 326ea9a..c1b2066 100644 --- a/src/db/Db.ts +++ b/src/db/Db.ts @@ -96,6 +96,9 @@ class Db { 'country', 'postalCode', 'description', + 'battery', + 'speed', + 'accuracy', ].reduce((acc: any, name: string) => { acc[name] = process.env[this.prefixedEnv(name)]; if (!acc[name]?.length && (requiredColumns[name] || opts.locationUrl === opts.url)) { diff --git a/src/db/migrations/001_add_metadata_to_location_points.ts b/src/db/migrations/001_add_metadata_to_location_points.ts new file mode 100644 index 0000000..5744546 --- /dev/null +++ b/src/db/migrations/001_add_metadata_to_location_points.ts @@ -0,0 +1,41 @@ +async function addLocationHistoryColumns(query: { context: any }) { + const { DataTypes } = require('sequelize'); + + await query.context.addColumn($db.locationTable, $db.locationTableColumns['battery'], { + type: DataTypes.FLOAT, + allowNull: true + }); + + await query.context.addColumn($db.locationTable, $db.locationTableColumns['speed'], { + type: DataTypes.FLOAT, + allowNull: true + }); + + await query.context.addColumn($db.locationTable, $db.locationTableColumns['accuracy'], { + type: DataTypes.FLOAT, + allowNull: true + }); +} + +async function removeLocationHistoryColumns(query: { context: any }) { + await query.context.removeColumn($db.locationTable, $db.locationTableColumns['battery']); + await query.context.removeColumn($db.locationTable, $db.locationTableColumns['speed']); + await query.context.removeColumn($db.locationTable, $db.locationTableColumns['accuracy']); +} + +const addMetadataToLocationPoints = { + up: async (query: { context: any }) => { + await addLocationHistoryColumns({ context: query.context }); + }, + + down: async (query: { context: any }) => { + if ($db.locationUrl !== $db.url) { + console.log('The location history table is stored on an external database, skipping deletion'); + return; + } + + await removeLocationHistoryColumns({ context: query.context }); + }, +} + +module.exports = addMetadataToLocationPoints; diff --git a/src/db/types/GPSData.ts b/src/db/types/GPSData.ts index 72c249e..6343454 100644 --- a/src/db/types/GPSData.ts +++ b/src/db/types/GPSData.ts @@ -74,6 +74,30 @@ function GPSData(locationTableColumns: Record<string, string>): Record<string, a }; } + const batteryCol: string = locationTableColumns['battery']; + if (batteryCol?.length) { + typeDef[batteryCol] = { + type: DataTypes.FLOAT, + allowNull: true + }; + } + + const speedCol: string = locationTableColumns['speed']; + if (speedCol?.length) { + typeDef[speedCol] = { + type: DataTypes.FLOAT, + allowNull: true + }; + } + + const accuracyCol: string = locationTableColumns['accuracy']; + if (accuracyCol?.length) { + typeDef[accuracyCol] = { + type: DataTypes.FLOAT, + allowNull: true + }; + } + typeDef[locationTableColumns['timestamp']] = { type: DataTypes.DATE, defaultValue: DataTypes.NOW diff --git a/src/models/GPSPoint.ts b/src/models/GPSPoint.ts index a90ee4a..e1cff6c 100644 --- a/src/models/GPSPoint.ts +++ b/src/models/GPSPoint.ts @@ -9,6 +9,9 @@ class GPSPoint { public country: string | null; public postalCode: string | null; public description: string | null; + public battery: number | null; + public speed: number | null; + public accuracy: number | null; public timestamp: Date; constructor(record: any) { @@ -22,6 +25,9 @@ class GPSPoint { this.country = record.country; this.postalCode = record.postalCode; this.description = record.description; + this.battery = record.battery; + this.speed = record.speed; + this.accuracy = record.accuracy; this.timestamp = record.timestamp; } } diff --git a/src/repos/Location.ts b/src/repos/Location.ts index 345fe44..946cc15 100644 --- a/src/repos/Location.ts +++ b/src/repos/Location.ts @@ -41,6 +41,9 @@ class Location { country: data[mappings.country], postalCode: data[mappings.postalCode], description: data[mappings.description], + battery: data[mappings.battery], + speed: data[mappings.speed], + accuracy: data[mappings.accuracy], timestamp: data[mappings.timestamp], }); }); @@ -78,6 +81,9 @@ class Location { country: data[mappings.country], postalCode: data[mappings.postalCode], description: data[mappings.description], + battery: data[mappings.battery], + speed: data[mappings.speed], + accuracy: data[mappings.accuracy], timestamp: data[mappings.timestamp], }); }); @@ -111,6 +117,9 @@ class Location { [mappings.country]: p.country, [mappings.postalCode]: p.postalcode, [mappings.description]: p.description, + [mappings.battery]: p.battery, + [mappings.speed]: p.speed, + [mappings.accuracy]: p.accuracy, [mappings.timestamp]: p.timestamp } }, @@ -129,6 +138,9 @@ class Location { country: data[mappings.country], postalCode: data[mappings.postalCode], description: data[mappings.description], + battery: data[mappings.battery], + speed: data[mappings.speed], + accuracy: data[mappings.accuracy], timestamp: data[mappings.timestamp], }); }); @@ -162,6 +174,9 @@ class Location { [mappings.country]: p.country, [mappings.postalCode]: p.postalcode, [mappings.description]: p.description, + [mappings.battery]: p.battery, + [mappings.speed]: p.speed, + [mappings.accuracy]: p.accuracy, [mappings.timestamp]: p.timestamp } }),