From da07d8cd3e794839e35d88b341cfca6d26498d02 Mon Sep 17 00:00:00 2001 From: Fergal Moran Date: Thu, 1 Feb 2024 20:43:23 +0000 Subject: [PATCH] Added device connect route --- .idea/dataSources.xml | 12 + Makefile | 35 ++ bun.lockb | Bin 270760 -> 272151 bytes hosting/docker/development/Dockerfile | 9 + .../docker/development/docker-compose.yaml | 10 + package.json | 9 +- scripts/reset.sh | 10 +- src/app/api/device/connect/route.ts | 37 ++ src/components/maps/map-marker.tsx | 32 +- src/lib/services/auth/api-key.ts | 6 + .../db/migrations/0004_lying_jack_murdock.sql | 1 + .../migrations/0005_furry_doctor_octopus.sql | 1 + .../migrations/0006_wooden_next_avengers.sql | 1 + .../db/migrations/meta/0004_snapshot.json | 432 +++++++++++++++++ .../db/migrations/meta/0005_snapshot.json | 433 ++++++++++++++++++ .../db/migrations/meta/0006_snapshot.json | 432 +++++++++++++++++ src/server/db/migrations/meta/_journal.json | 21 + src/server/db/schema/devices.ts | 1 + 18 files changed, 1445 insertions(+), 37 deletions(-) create mode 100644 .idea/dataSources.xml create mode 100644 Makefile create mode 100644 hosting/docker/development/Dockerfile create mode 100644 hosting/docker/development/docker-compose.yaml create mode 100644 src/app/api/device/connect/route.ts create mode 100644 src/lib/services/auth/api-key.ts create mode 100644 src/server/db/migrations/0004_lying_jack_murdock.sql create mode 100644 src/server/db/migrations/0005_furry_doctor_octopus.sql create mode 100644 src/server/db/migrations/0006_wooden_next_avengers.sql create mode 100644 src/server/db/migrations/meta/0004_snapshot.json create mode 100644 src/server/db/migrations/meta/0005_snapshot.json create mode 100644 src/server/db/migrations/meta/0006_snapshot.json diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..1d8c1b2 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,12 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/kidarr + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7223a27 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +.PHONY: build-development +build-development: ## Build the development docker image. + docker compose -f hosting/docker/development/docker-compose.yaml build + +.PHONY: start-development +start-development: ## Start the development docker container. + docker compose -f hosting/docker/development/docker-compose.yaml up -d + +.PHONY: stop-development +stop-development: ## Stop the development docker container. + docker compose -f hosting/docker/development/docker-compose.yaml down + +.PHONY: build-staging +build-staging: ## Build the staging docker image. + docker compose -f hosting/docker/staging/docker-compose.yaml build + +.PHONY: start-staging +start-staging: ## Start the staging docker container. + docker compose -f hosting/docker/staging/docker-compose.yaml up -d + +.PHONY: stop-staging +stop-staging: ## Stop the staging docker container. + docker compose -f hosting/docker/staging/docker-compose.yaml down + +.PHONY: build-production +build-production: ## Build the production docker image. + docker compose -f hosting/docker/production/docker-compose.yaml build + +.PHONY: start-production +start-production: ## Start the production docker container. + docker compose -f hosting/docker/production/docker-compose.yaml up -d + +.PHONY: stop-production +stop-production: ## Stop the production docker container. + docker compose -f hosting/docker/production/docker-compose.yaml down diff --git a/bun.lockb b/bun.lockb index 197b1620bc27cca69abd70dc1a8795e3496c4f22..fea657b8f1ee630ad25a47318e59826cbcb7d0d2 100755 GIT binary patch delta 49655 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 delta 48301 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≪mbOMA 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 { + if (req.method !== "POST") { + return badRequest("Invalid method"); + } + + const { deviceId, childId, deviceName } = + (await req.json()) as DeviceConnectRequest; + + if (!deviceId || !childId || !deviceName) { + return badRequest("Invalid request"); + } + + const child = (await getChildById(childId)).child; + + if (!child) { + return badRequest("Invalid child"); + } + + const apiKey = createApiKey(); + + await createDevice({ + childId: child.id, + deviceId: deviceId, + name: deviceName, + apiKey: apiKey, + }); +}; diff --git a/src/components/maps/map-marker.tsx b/src/components/maps/map-marker.tsx index 36d48c3..d09c7ac 100644 --- a/src/components/maps/map-marker.tsx +++ b/src/components/maps/map-marker.tsx @@ -84,41 +84,19 @@ const MapMarker: React.FC = ({ - {/**/} - {/*

*/} - {/**/} - +
{deviceName}
-
Last seen - {humanizeDate(timestamp)}
- - - + + + - + diff --git a/src/lib/services/auth/api-key.ts b/src/lib/services/auth/api-key.ts new file mode 100644 index 0000000..a81d443 --- /dev/null +++ b/src/lib/services/auth/api-key.ts @@ -0,0 +1,6 @@ +import generateApiKey from "generate-api-key"; + +const createApiKey = () => + generateApiKey({ method: "string", length: 256 }) as string; + +export { createApiKey }; diff --git a/src/server/db/migrations/0004_lying_jack_murdock.sql b/src/server/db/migrations/0004_lying_jack_murdock.sql new file mode 100644 index 0000000..5a707a4 --- /dev/null +++ b/src/server/db/migrations/0004_lying_jack_murdock.sql @@ -0,0 +1 @@ +ALTER TABLE "devices" ADD COLUMN "api_key" varchar(256) NOT NULL; \ No newline at end of file diff --git a/src/server/db/migrations/0005_furry_doctor_octopus.sql b/src/server/db/migrations/0005_furry_doctor_octopus.sql new file mode 100644 index 0000000..a0d406b --- /dev/null +++ b/src/server/db/migrations/0005_furry_doctor_octopus.sql @@ -0,0 +1 @@ +ALTER TABLE "devices" ALTER COLUMN "api_key" SET DEFAULT 'asdsad'; \ No newline at end of file diff --git a/src/server/db/migrations/0006_wooden_next_avengers.sql b/src/server/db/migrations/0006_wooden_next_avengers.sql new file mode 100644 index 0000000..7ce7d8b --- /dev/null +++ b/src/server/db/migrations/0006_wooden_next_avengers.sql @@ -0,0 +1 @@ +ALTER TABLE "devices" ALTER COLUMN "api_key" DROP DEFAULT; \ No newline at end of file diff --git a/src/server/db/migrations/meta/0004_snapshot.json b/src/server/db/migrations/meta/0004_snapshot.json new file mode 100644 index 0000000..1bccfd9 --- /dev/null +++ b/src/server/db/migrations/meta/0004_snapshot.json @@ -0,0 +1,432 @@ +{ + "id": "8b1ceb6b-cc16-4e61-b4b3-94e34f58c637", + "prevId": "82ea1092-603e-47a9-ad4c-9ca7995afb8d", + "version": "5", + "dialect": "pg", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "children": { + "name": "children", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "avatar": { + "name": "avatar", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "children_user_id_user_id_fk": { + "name": "children_user_id_user_id_fk", + "tableFrom": "children", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "devices": { + "name": "devices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "child_id": { + "name": "child_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "devices_child_id_children_id_fk": { + "name": "devices_child_id_children_id_fk", + "tableFrom": "devices", + "tableTo": "children", + "columnsFrom": [ + "child_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "devices_user_id_user_id_fk": { + "name": "devices_user_id_user_id_fk", + "tableFrom": "devices", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "pings": { + "name": "pings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "pings_device_id_devices_id_fk": { + "name": "pings_device_id_devices_id_fk", + "tableFrom": "pings", + "tableTo": "devices", + "columnsFrom": [ + "device_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pings_user_id_user_id_fk": { + "name": "pings_user_id_user_id_fk", + "tableFrom": "pings", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/0005_snapshot.json b/src/server/db/migrations/meta/0005_snapshot.json new file mode 100644 index 0000000..d9f4ace --- /dev/null +++ b/src/server/db/migrations/meta/0005_snapshot.json @@ -0,0 +1,433 @@ +{ + "id": "f4a26526-6eed-4f4d-a8f2-599c92ae78d7", + "prevId": "8b1ceb6b-cc16-4e61-b4b3-94e34f58c637", + "version": "5", + "dialect": "pg", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "children": { + "name": "children", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "avatar": { + "name": "avatar", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "children_user_id_user_id_fk": { + "name": "children_user_id_user_id_fk", + "tableFrom": "children", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "devices": { + "name": "devices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true, + "default": "'asdsad'" + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "child_id": { + "name": "child_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "devices_child_id_children_id_fk": { + "name": "devices_child_id_children_id_fk", + "tableFrom": "devices", + "tableTo": "children", + "columnsFrom": [ + "child_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "devices_user_id_user_id_fk": { + "name": "devices_user_id_user_id_fk", + "tableFrom": "devices", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "pings": { + "name": "pings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "pings_device_id_devices_id_fk": { + "name": "pings_device_id_devices_id_fk", + "tableFrom": "pings", + "tableTo": "devices", + "columnsFrom": [ + "device_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pings_user_id_user_id_fk": { + "name": "pings_user_id_user_id_fk", + "tableFrom": "pings", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/0006_snapshot.json b/src/server/db/migrations/meta/0006_snapshot.json new file mode 100644 index 0000000..a785d71 --- /dev/null +++ b/src/server/db/migrations/meta/0006_snapshot.json @@ -0,0 +1,432 @@ +{ + "id": "58c0704d-ef7a-4d9f-8f5a-e11be0d6c96b", + "prevId": "f4a26526-6eed-4f4d-a8f2-599c92ae78d7", + "version": "5", + "dialect": "pg", + "tables": { + "account": { + "name": "account", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "name": "account_provider_providerAccountId_pk", + "columns": [ + "provider", + "providerAccountId" + ] + } + }, + "uniqueConstraints": {} + }, + "children": { + "name": "children", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "avatar": { + "name": "avatar", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "children_user_id_user_id_fk": { + "name": "children_user_id_user_id_fk", + "tableFrom": "children", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "devices": { + "name": "devices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "api_key": { + "name": "api_key", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "child_id": { + "name": "child_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "devices_child_id_children_id_fk": { + "name": "devices_child_id_children_id_fk", + "tableFrom": "devices", + "tableTo": "children", + "columnsFrom": [ + "child_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "devices_user_id_user_id_fk": { + "name": "devices_user_id_user_id_fk", + "tableFrom": "devices", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "pings": { + "name": "pings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(191)", + "primaryKey": true, + "notNull": true + }, + "latitude": { + "name": "latitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "longitude": { + "name": "longitude", + "type": "real", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "device_id": { + "name": "device_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "pings_device_id_devices_id_fk": { + "name": "pings_device_id_devices_id_fk", + "tableFrom": "pings", + "tableTo": "devices", + "columnsFrom": [ + "device_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pings_user_id_user_id_fk": { + "name": "pings_user_id_user_id_fk", + "tableFrom": "pings", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "emailVerified": { + "name": "emailVerified", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "schema": "", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "name": "verificationToken_identifier_token_pk", + "columns": [ + "identifier", + "token" + ] + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/src/server/db/migrations/meta/_journal.json b/src/server/db/migrations/meta/_journal.json index 2a76fe3..f146b64 100644 --- a/src/server/db/migrations/meta/_journal.json +++ b/src/server/db/migrations/meta/_journal.json @@ -29,6 +29,27 @@ "when": 1706731530273, "tag": "0003_luxuriant_nightshade", "breakpoints": true + }, + { + "idx": 4, + "version": "5", + "when": 1706812885568, + "tag": "0004_lying_jack_murdock", + "breakpoints": true + }, + { + "idx": 5, + "version": "5", + "when": 1706812942062, + "tag": "0005_furry_doctor_octopus", + "breakpoints": true + }, + { + "idx": 6, + "version": "5", + "when": 1706812968116, + "tag": "0006_wooden_next_avengers", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/db/schema/devices.ts b/src/server/db/schema/devices.ts index 326cca7..eaf9ab6 100644 --- a/src/server/db/schema/devices.ts +++ b/src/server/db/schema/devices.ts @@ -14,6 +14,7 @@ export const devices = pgTable("devices", { .primaryKey() .$defaultFn(() => randomUUID()), name: varchar("name", { length: 256 }).notNull(), + apiKey: varchar("api_key", { length: 256 }).notNull(), deviceId: varchar("device_id", { length: 256 }).notNull(), childId: varchar("child_id", { length: 256 }) .references(() => children.id, { onDelete: "cascade" })