diff --git a/drizzle/0016_lazy_kinsey_walden.sql b/drizzle/0016_lazy_kinsey_walden.sql
new file mode 100644
index 0000000..4d1672d
--- /dev/null
+++ b/drizzle/0016_lazy_kinsey_walden.sql
@@ -0,0 +1,32 @@
+CREATE TYPE "public"."market_order_status" AS ENUM('awaiting_approval', 'approved', 'fulfilled');--> statement-breakpoint
+CREATE TABLE "market_item" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "createdBy" integer,
+ "name" text NOT NULL,
+ "description" text NOT NULL,
+ "image" text NOT NULL,
+ "minRequiredShopScore" integer DEFAULT 0 NOT NULL,
+ "minShopScore" integer NOT NULL,
+ "maxShopScore" integer NOT NULL,
+ "maxPrice" integer NOT NULL,
+ "minPrice" integer NOT NULL,
+ "isPublic" boolean DEFAULT false NOT NULL,
+ "deleted" boolean DEFAULT false NOT NULL,
+ "createdAt" timestamp DEFAULT now() NOT NULL,
+ "updatedAt" timestamp DEFAULT now() NOT NULL
+);
+--> statement-breakpoint
+CREATE TABLE "market_item_order" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "userId" integer,
+ "addressId" text NOT NULL,
+ "bricksPaid" integer NOT NULL,
+ "status" "market_order_status" DEFAULT 'awaiting_approval' NOT NULL,
+ "userNotes" text NOT NULL,
+ "notes" text NOT NULL,
+ "deleted" boolean DEFAULT false NOT NULL,
+ "createdAt" timestamp DEFAULT now() NOT NULL
+);
+--> statement-breakpoint
+ALTER TABLE "market_item" ADD CONSTRAINT "market_item_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "market_item_order" ADD CONSTRAINT "market_item_order_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;
\ No newline at end of file
diff --git a/drizzle/0017_long_greymalkin.sql b/drizzle/0017_long_greymalkin.sql
new file mode 100644
index 0000000..a15f9d7
--- /dev/null
+++ b/drizzle/0017_long_greymalkin.sql
@@ -0,0 +1,2 @@
+ALTER TYPE "public"."market_order_status" ADD VALUE 'denied';--> statement-breakpoint
+ALTER TYPE "public"."market_order_status" ADD VALUE 'refunded';
\ No newline at end of file
diff --git a/drizzle/0018_sour_roughhouse.sql b/drizzle/0018_sour_roughhouse.sql
new file mode 100644
index 0000000..4a680e5
--- /dev/null
+++ b/drizzle/0018_sour_roughhouse.sql
@@ -0,0 +1 @@
+ALTER TABLE "market_item_order" ALTER COLUMN "notes" DROP NOT NULL;
\ No newline at end of file
diff --git a/drizzle/0019_wide_gamora.sql b/drizzle/0019_wide_gamora.sql
new file mode 100644
index 0000000..11031a9
--- /dev/null
+++ b/drizzle/0019_wide_gamora.sql
@@ -0,0 +1 @@
+ALTER TABLE "market_item_order" ALTER COLUMN "userId" SET NOT NULL;
\ No newline at end of file
diff --git a/drizzle/meta/0016_snapshot.json b/drizzle/meta/0016_snapshot.json
new file mode 100644
index 0000000..2f3871d
--- /dev/null
+++ b/drizzle/meta/0016_snapshot.json
@@ -0,0 +1,1099 @@
+{
+ "id": "af6c7146-421a-48ea-88a9-7abbde335bb7",
+ "prevId": "1299d59c-43b6-46a5-9557-3c51b87eac07",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.devlog": {
+ "name": "devlog",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timeSpent": {
+ "name": "timeSpent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "devlog_userId_user_id_fk": {
+ "name": "devlog_userId_user_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "devlog_projectId_project_id_fk": {
+ "name": "devlog_projectId_project_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.legion_review": {
+ "name": "legion_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filamentUsed": {
+ "name": "filamentUsed",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "legion_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "legion_review_userId_user_id_fk": {
+ "name": "legion_review_userId_user_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "legion_review_projectId_project_id_fk": {
+ "name": "legion_review_projectId_project_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item": {
+ "name": "market_item",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "createdBy": {
+ "name": "createdBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minRequiredShopScore": {
+ "name": "minRequiredShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "minShopScore": {
+ "name": "minShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxShopScore": {
+ "name": "maxShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxPrice": {
+ "name": "maxPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minPrice": {
+ "name": "minPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "isPublic": {
+ "name": "isPublic",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_createdBy_user_id_fk": {
+ "name": "market_item_createdBy_user_id_fk",
+ "tableFrom": "market_item",
+ "tableTo": "user",
+ "columnsFrom": [
+ "createdBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item_order": {
+ "name": "market_item_order",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "addressId": {
+ "name": "addressId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bricksPaid": {
+ "name": "bricksPaid",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "market_order_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'awaiting_approval'"
+ },
+ "userNotes": {
+ "name": "userNotes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_order_userId_user_id_fk": {
+ "name": "market_item_order_userId_user_id_fk",
+ "tableFrom": "market_item_order",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.project": {
+ "name": "project",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'building'"
+ },
+ "printedBy": {
+ "name": "printedBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "submittedToAirtable": {
+ "name": "submittedToAirtable",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "project_userId_user_id_fk": {
+ "name": "project_userId_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "project_printedBy_user_id_fk": {
+ "name": "project_printedBy_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "printedBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expiresAt": {
+ "name": "expiresAt",
+ "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": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.ship": {
+ "name": "ship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "ship_userId_user_id_fk": {
+ "name": "ship_userId_user_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "ship_projectId_project_id_fk": {
+ "name": "ship_projectId_project_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t1_review": {
+ "name": "t1_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "t1_review_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t1_review_userId_user_id_fk": {
+ "name": "t1_review_userId_user_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t1_review_projectId_project_id_fk": {
+ "name": "t1_review_projectId_project_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t2_review": {
+ "name": "t2_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "currencyMultiplier": {
+ "name": "currencyMultiplier",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t2_review_userId_user_id_fk": {
+ "name": "t2_review_userId_user_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t2_review_projectId_project_id_fk": {
+ "name": "t2_review_projectId_project_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "idvId": {
+ "name": "idvId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "idvToken": {
+ "name": "idvToken",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slackId": {
+ "name": "slackId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "profilePicture": {
+ "name": "profilePicture",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "hackatimeTrust": {
+ "name": "hackatimeTrust",
+ "type": "hackatime_trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "trust": {
+ "name": "trust",
+ "type": "trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'blue'"
+ },
+ "clay": {
+ "name": "clay",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "brick": {
+ "name": "brick",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "shopScore": {
+ "name": "shopScore",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "hasBasePrinter": {
+ "name": "hasBasePrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT1Review": {
+ "name": "hasT1Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT2Review": {
+ "name": "hasT2Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasAdmin": {
+ "name": "hasAdmin",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "isPrinter": {
+ "name": "isPrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "lastLoginAt": {
+ "name": "lastLoginAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "user_idvId_unique": {
+ "name": "user_idvId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "idvId"
+ ]
+ },
+ "user_slackId_unique": {
+ "name": "user_slackId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slackId"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.editor_file_type": {
+ "name": "editor_file_type",
+ "schema": "public",
+ "values": [
+ "url",
+ "upload"
+ ]
+ },
+ "public.hackatime_trust": {
+ "name": "hackatime_trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ },
+ "public.legion_action": {
+ "name": "legion_action",
+ "schema": "public",
+ "values": [
+ "mark_for_printing",
+ "unmark_for_printing",
+ "print",
+ "add_comment",
+ "reject",
+ "already_printed"
+ ]
+ },
+ "public.market_order_status": {
+ "name": "market_order_status",
+ "schema": "public",
+ "values": [
+ "awaiting_approval",
+ "approved",
+ "fulfilled"
+ ]
+ },
+ "public.project_audit_log_type": {
+ "name": "project_audit_log_type",
+ "schema": "public",
+ "values": [
+ "create",
+ "update",
+ "delete"
+ ]
+ },
+ "public.status": {
+ "name": "status",
+ "schema": "public",
+ "values": [
+ "building",
+ "submitted",
+ "t1_approved",
+ "printing",
+ "printed",
+ "t2_approved",
+ "finalized",
+ "rejected",
+ "rejected_locked"
+ ]
+ },
+ "public.t1_review_action": {
+ "name": "t1_review_action",
+ "schema": "public",
+ "values": [
+ "approve",
+ "approve_no_print",
+ "add_comment",
+ "reject",
+ "reject_lock"
+ ]
+ },
+ "public.trust": {
+ "name": "trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0017_snapshot.json b/drizzle/meta/0017_snapshot.json
new file mode 100644
index 0000000..fa2bb6e
--- /dev/null
+++ b/drizzle/meta/0017_snapshot.json
@@ -0,0 +1,1101 @@
+{
+ "id": "c1769f02-cca9-40e9-afe3-ed329a1f74c7",
+ "prevId": "af6c7146-421a-48ea-88a9-7abbde335bb7",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.devlog": {
+ "name": "devlog",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timeSpent": {
+ "name": "timeSpent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "devlog_userId_user_id_fk": {
+ "name": "devlog_userId_user_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "devlog_projectId_project_id_fk": {
+ "name": "devlog_projectId_project_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.legion_review": {
+ "name": "legion_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filamentUsed": {
+ "name": "filamentUsed",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "legion_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "legion_review_userId_user_id_fk": {
+ "name": "legion_review_userId_user_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "legion_review_projectId_project_id_fk": {
+ "name": "legion_review_projectId_project_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item": {
+ "name": "market_item",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "createdBy": {
+ "name": "createdBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minRequiredShopScore": {
+ "name": "minRequiredShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "minShopScore": {
+ "name": "minShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxShopScore": {
+ "name": "maxShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxPrice": {
+ "name": "maxPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minPrice": {
+ "name": "minPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "isPublic": {
+ "name": "isPublic",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_createdBy_user_id_fk": {
+ "name": "market_item_createdBy_user_id_fk",
+ "tableFrom": "market_item",
+ "tableTo": "user",
+ "columnsFrom": [
+ "createdBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item_order": {
+ "name": "market_item_order",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "addressId": {
+ "name": "addressId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bricksPaid": {
+ "name": "bricksPaid",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "market_order_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'awaiting_approval'"
+ },
+ "userNotes": {
+ "name": "userNotes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_order_userId_user_id_fk": {
+ "name": "market_item_order_userId_user_id_fk",
+ "tableFrom": "market_item_order",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.project": {
+ "name": "project",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'building'"
+ },
+ "printedBy": {
+ "name": "printedBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "submittedToAirtable": {
+ "name": "submittedToAirtable",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "project_userId_user_id_fk": {
+ "name": "project_userId_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "project_printedBy_user_id_fk": {
+ "name": "project_printedBy_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "printedBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expiresAt": {
+ "name": "expiresAt",
+ "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": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.ship": {
+ "name": "ship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "ship_userId_user_id_fk": {
+ "name": "ship_userId_user_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "ship_projectId_project_id_fk": {
+ "name": "ship_projectId_project_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t1_review": {
+ "name": "t1_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "t1_review_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t1_review_userId_user_id_fk": {
+ "name": "t1_review_userId_user_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t1_review_projectId_project_id_fk": {
+ "name": "t1_review_projectId_project_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t2_review": {
+ "name": "t2_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "currencyMultiplier": {
+ "name": "currencyMultiplier",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t2_review_userId_user_id_fk": {
+ "name": "t2_review_userId_user_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t2_review_projectId_project_id_fk": {
+ "name": "t2_review_projectId_project_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "idvId": {
+ "name": "idvId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "idvToken": {
+ "name": "idvToken",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slackId": {
+ "name": "slackId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "profilePicture": {
+ "name": "profilePicture",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "hackatimeTrust": {
+ "name": "hackatimeTrust",
+ "type": "hackatime_trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "trust": {
+ "name": "trust",
+ "type": "trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'blue'"
+ },
+ "clay": {
+ "name": "clay",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "brick": {
+ "name": "brick",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "shopScore": {
+ "name": "shopScore",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "hasBasePrinter": {
+ "name": "hasBasePrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT1Review": {
+ "name": "hasT1Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT2Review": {
+ "name": "hasT2Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasAdmin": {
+ "name": "hasAdmin",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "isPrinter": {
+ "name": "isPrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "lastLoginAt": {
+ "name": "lastLoginAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "user_idvId_unique": {
+ "name": "user_idvId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "idvId"
+ ]
+ },
+ "user_slackId_unique": {
+ "name": "user_slackId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slackId"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.editor_file_type": {
+ "name": "editor_file_type",
+ "schema": "public",
+ "values": [
+ "url",
+ "upload"
+ ]
+ },
+ "public.hackatime_trust": {
+ "name": "hackatime_trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ },
+ "public.legion_action": {
+ "name": "legion_action",
+ "schema": "public",
+ "values": [
+ "mark_for_printing",
+ "unmark_for_printing",
+ "print",
+ "add_comment",
+ "reject",
+ "already_printed"
+ ]
+ },
+ "public.market_order_status": {
+ "name": "market_order_status",
+ "schema": "public",
+ "values": [
+ "awaiting_approval",
+ "approved",
+ "fulfilled",
+ "denied",
+ "refunded"
+ ]
+ },
+ "public.project_audit_log_type": {
+ "name": "project_audit_log_type",
+ "schema": "public",
+ "values": [
+ "create",
+ "update",
+ "delete"
+ ]
+ },
+ "public.status": {
+ "name": "status",
+ "schema": "public",
+ "values": [
+ "building",
+ "submitted",
+ "t1_approved",
+ "printing",
+ "printed",
+ "t2_approved",
+ "finalized",
+ "rejected",
+ "rejected_locked"
+ ]
+ },
+ "public.t1_review_action": {
+ "name": "t1_review_action",
+ "schema": "public",
+ "values": [
+ "approve",
+ "approve_no_print",
+ "add_comment",
+ "reject",
+ "reject_lock"
+ ]
+ },
+ "public.trust": {
+ "name": "trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0018_snapshot.json b/drizzle/meta/0018_snapshot.json
new file mode 100644
index 0000000..9268cb2
--- /dev/null
+++ b/drizzle/meta/0018_snapshot.json
@@ -0,0 +1,1101 @@
+{
+ "id": "f03cfd63-e7c6-44fa-902c-2f9237b9ee96",
+ "prevId": "c1769f02-cca9-40e9-afe3-ed329a1f74c7",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.devlog": {
+ "name": "devlog",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timeSpent": {
+ "name": "timeSpent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "devlog_userId_user_id_fk": {
+ "name": "devlog_userId_user_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "devlog_projectId_project_id_fk": {
+ "name": "devlog_projectId_project_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.legion_review": {
+ "name": "legion_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filamentUsed": {
+ "name": "filamentUsed",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "legion_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "legion_review_userId_user_id_fk": {
+ "name": "legion_review_userId_user_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "legion_review_projectId_project_id_fk": {
+ "name": "legion_review_projectId_project_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item": {
+ "name": "market_item",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "createdBy": {
+ "name": "createdBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minRequiredShopScore": {
+ "name": "minRequiredShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "minShopScore": {
+ "name": "minShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxShopScore": {
+ "name": "maxShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxPrice": {
+ "name": "maxPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minPrice": {
+ "name": "minPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "isPublic": {
+ "name": "isPublic",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_createdBy_user_id_fk": {
+ "name": "market_item_createdBy_user_id_fk",
+ "tableFrom": "market_item",
+ "tableTo": "user",
+ "columnsFrom": [
+ "createdBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item_order": {
+ "name": "market_item_order",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "addressId": {
+ "name": "addressId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bricksPaid": {
+ "name": "bricksPaid",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "market_order_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'awaiting_approval'"
+ },
+ "userNotes": {
+ "name": "userNotes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_order_userId_user_id_fk": {
+ "name": "market_item_order_userId_user_id_fk",
+ "tableFrom": "market_item_order",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.project": {
+ "name": "project",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'building'"
+ },
+ "printedBy": {
+ "name": "printedBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "submittedToAirtable": {
+ "name": "submittedToAirtable",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "project_userId_user_id_fk": {
+ "name": "project_userId_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "project_printedBy_user_id_fk": {
+ "name": "project_printedBy_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "printedBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expiresAt": {
+ "name": "expiresAt",
+ "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": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.ship": {
+ "name": "ship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "ship_userId_user_id_fk": {
+ "name": "ship_userId_user_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "ship_projectId_project_id_fk": {
+ "name": "ship_projectId_project_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t1_review": {
+ "name": "t1_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "t1_review_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t1_review_userId_user_id_fk": {
+ "name": "t1_review_userId_user_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t1_review_projectId_project_id_fk": {
+ "name": "t1_review_projectId_project_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t2_review": {
+ "name": "t2_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "currencyMultiplier": {
+ "name": "currencyMultiplier",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t2_review_userId_user_id_fk": {
+ "name": "t2_review_userId_user_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t2_review_projectId_project_id_fk": {
+ "name": "t2_review_projectId_project_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "idvId": {
+ "name": "idvId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "idvToken": {
+ "name": "idvToken",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slackId": {
+ "name": "slackId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "profilePicture": {
+ "name": "profilePicture",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "hackatimeTrust": {
+ "name": "hackatimeTrust",
+ "type": "hackatime_trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "trust": {
+ "name": "trust",
+ "type": "trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'blue'"
+ },
+ "clay": {
+ "name": "clay",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "brick": {
+ "name": "brick",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "shopScore": {
+ "name": "shopScore",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "hasBasePrinter": {
+ "name": "hasBasePrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT1Review": {
+ "name": "hasT1Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT2Review": {
+ "name": "hasT2Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasAdmin": {
+ "name": "hasAdmin",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "isPrinter": {
+ "name": "isPrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "lastLoginAt": {
+ "name": "lastLoginAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "user_idvId_unique": {
+ "name": "user_idvId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "idvId"
+ ]
+ },
+ "user_slackId_unique": {
+ "name": "user_slackId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slackId"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.editor_file_type": {
+ "name": "editor_file_type",
+ "schema": "public",
+ "values": [
+ "url",
+ "upload"
+ ]
+ },
+ "public.hackatime_trust": {
+ "name": "hackatime_trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ },
+ "public.legion_action": {
+ "name": "legion_action",
+ "schema": "public",
+ "values": [
+ "mark_for_printing",
+ "unmark_for_printing",
+ "print",
+ "add_comment",
+ "reject",
+ "already_printed"
+ ]
+ },
+ "public.market_order_status": {
+ "name": "market_order_status",
+ "schema": "public",
+ "values": [
+ "awaiting_approval",
+ "approved",
+ "fulfilled",
+ "denied",
+ "refunded"
+ ]
+ },
+ "public.project_audit_log_type": {
+ "name": "project_audit_log_type",
+ "schema": "public",
+ "values": [
+ "create",
+ "update",
+ "delete"
+ ]
+ },
+ "public.status": {
+ "name": "status",
+ "schema": "public",
+ "values": [
+ "building",
+ "submitted",
+ "t1_approved",
+ "printing",
+ "printed",
+ "t2_approved",
+ "finalized",
+ "rejected",
+ "rejected_locked"
+ ]
+ },
+ "public.t1_review_action": {
+ "name": "t1_review_action",
+ "schema": "public",
+ "values": [
+ "approve",
+ "approve_no_print",
+ "add_comment",
+ "reject",
+ "reject_lock"
+ ]
+ },
+ "public.trust": {
+ "name": "trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/0019_snapshot.json b/drizzle/meta/0019_snapshot.json
new file mode 100644
index 0000000..a1e85ba
--- /dev/null
+++ b/drizzle/meta/0019_snapshot.json
@@ -0,0 +1,1101 @@
+{
+ "id": "2406dbb1-cdda-4c04-b6f1-363172327705",
+ "prevId": "f03cfd63-e7c6-44fa-902c-2f9237b9ee96",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.devlog": {
+ "name": "devlog",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timeSpent": {
+ "name": "timeSpent",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "model": {
+ "name": "model",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "devlog_userId_user_id_fk": {
+ "name": "devlog_userId_user_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "devlog_projectId_project_id_fk": {
+ "name": "devlog_projectId_project_id_fk",
+ "tableFrom": "devlog",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.legion_review": {
+ "name": "legion_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filamentUsed": {
+ "name": "filamentUsed",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "legion_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "legion_review_userId_user_id_fk": {
+ "name": "legion_review_userId_user_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "legion_review_projectId_project_id_fk": {
+ "name": "legion_review_projectId_project_id_fk",
+ "tableFrom": "legion_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item": {
+ "name": "market_item",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "createdBy": {
+ "name": "createdBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minRequiredShopScore": {
+ "name": "minRequiredShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "minShopScore": {
+ "name": "minShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxShopScore": {
+ "name": "maxShopScore",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "maxPrice": {
+ "name": "maxPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "minPrice": {
+ "name": "minPrice",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "isPublic": {
+ "name": "isPublic",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_createdBy_user_id_fk": {
+ "name": "market_item_createdBy_user_id_fk",
+ "tableFrom": "market_item",
+ "tableTo": "user",
+ "columnsFrom": [
+ "createdBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.market_item_order": {
+ "name": "market_item_order",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "addressId": {
+ "name": "addressId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "bricksPaid": {
+ "name": "bricksPaid",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "market_order_status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'awaiting_approval'"
+ },
+ "userNotes": {
+ "name": "userNotes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "market_item_order_userId_user_id_fk": {
+ "name": "market_item_order_userId_user_id_fk",
+ "tableFrom": "market_item_order",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.project": {
+ "name": "project",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "description": {
+ "name": "description",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "status",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'building'"
+ },
+ "printedBy": {
+ "name": "printedBy",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "submittedToAirtable": {
+ "name": "submittedToAirtable",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "deleted": {
+ "name": "deleted",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "project_userId_user_id_fk": {
+ "name": "project_userId_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "project_printedBy_user_id_fk": {
+ "name": "project_printedBy_user_id_fk",
+ "tableFrom": "project",
+ "tableTo": "user",
+ "columnsFrom": [
+ "printedBy"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expiresAt": {
+ "name": "expiresAt",
+ "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": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.ship": {
+ "name": "ship",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorFileType": {
+ "name": "editorFileType",
+ "type": "editor_file_type",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "editorUrl": {
+ "name": "editorUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "uploadedFileUrl": {
+ "name": "uploadedFileUrl",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "modelFile": {
+ "name": "modelFile",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "ship_userId_user_id_fk": {
+ "name": "ship_userId_user_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "ship_projectId_project_id_fk": {
+ "name": "ship_projectId_project_id_fk",
+ "tableFrom": "ship",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t1_review": {
+ "name": "t1_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "action": {
+ "name": "action",
+ "type": "t1_review_action",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t1_review_userId_user_id_fk": {
+ "name": "t1_review_userId_user_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t1_review_projectId_project_id_fk": {
+ "name": "t1_review_projectId_project_id_fk",
+ "tableFrom": "t1_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.t2_review": {
+ "name": "t2_review",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "userId": {
+ "name": "userId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "projectId": {
+ "name": "projectId",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "feedback": {
+ "name": "feedback",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "notes": {
+ "name": "notes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "currencyMultiplier": {
+ "name": "currencyMultiplier",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "timestamp": {
+ "name": "timestamp",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "t2_review_userId_user_id_fk": {
+ "name": "t2_review_userId_user_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "user",
+ "columnsFrom": [
+ "userId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ },
+ "t2_review_projectId_project_id_fk": {
+ "name": "t2_review_projectId_project_id_fk",
+ "tableFrom": "t2_review",
+ "tableTo": "project",
+ "columnsFrom": [
+ "projectId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "no action",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "idvId": {
+ "name": "idvId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "idvToken": {
+ "name": "idvToken",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "slackId": {
+ "name": "slackId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "profilePicture": {
+ "name": "profilePicture",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "hackatimeTrust": {
+ "name": "hackatimeTrust",
+ "type": "hackatime_trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "trust": {
+ "name": "trust",
+ "type": "trust",
+ "typeSchema": "public",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'blue'"
+ },
+ "clay": {
+ "name": "clay",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "brick": {
+ "name": "brick",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "shopScore": {
+ "name": "shopScore",
+ "type": "real",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "hasBasePrinter": {
+ "name": "hasBasePrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT1Review": {
+ "name": "hasT1Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasT2Review": {
+ "name": "hasT2Review",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "hasAdmin": {
+ "name": "hasAdmin",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "isPrinter": {
+ "name": "isPrinter",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "createdAt": {
+ "name": "createdAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "lastLoginAt": {
+ "name": "lastLoginAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "user_idvId_unique": {
+ "name": "user_idvId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "idvId"
+ ]
+ },
+ "user_slackId_unique": {
+ "name": "user_slackId_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "slackId"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {
+ "public.editor_file_type": {
+ "name": "editor_file_type",
+ "schema": "public",
+ "values": [
+ "url",
+ "upload"
+ ]
+ },
+ "public.hackatime_trust": {
+ "name": "hackatime_trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ },
+ "public.legion_action": {
+ "name": "legion_action",
+ "schema": "public",
+ "values": [
+ "mark_for_printing",
+ "unmark_for_printing",
+ "print",
+ "add_comment",
+ "reject",
+ "already_printed"
+ ]
+ },
+ "public.market_order_status": {
+ "name": "market_order_status",
+ "schema": "public",
+ "values": [
+ "awaiting_approval",
+ "approved",
+ "fulfilled",
+ "denied",
+ "refunded"
+ ]
+ },
+ "public.project_audit_log_type": {
+ "name": "project_audit_log_type",
+ "schema": "public",
+ "values": [
+ "create",
+ "update",
+ "delete"
+ ]
+ },
+ "public.status": {
+ "name": "status",
+ "schema": "public",
+ "values": [
+ "building",
+ "submitted",
+ "t1_approved",
+ "printing",
+ "printed",
+ "t2_approved",
+ "finalized",
+ "rejected",
+ "rejected_locked"
+ ]
+ },
+ "public.t1_review_action": {
+ "name": "t1_review_action",
+ "schema": "public",
+ "values": [
+ "approve",
+ "approve_no_print",
+ "add_comment",
+ "reject",
+ "reject_lock"
+ ]
+ },
+ "public.trust": {
+ "name": "trust",
+ "schema": "public",
+ "values": [
+ "green",
+ "blue",
+ "yellow",
+ "red"
+ ]
+ }
+ },
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
index a7d9ba3..36ecf62 100644
--- a/drizzle/meta/_journal.json
+++ b/drizzle/meta/_journal.json
@@ -113,6 +113,34 @@
"when": 1766163214868,
"tag": "0015_flaky_james_howlett",
"breakpoints": true
+ },
+ {
+ "idx": 16,
+ "version": "7",
+ "when": 1766430469939,
+ "tag": "0016_lazy_kinsey_walden",
+ "breakpoints": true
+ },
+ {
+ "idx": 17,
+ "version": "7",
+ "when": 1766436733390,
+ "tag": "0017_long_greymalkin",
+ "breakpoints": true
+ },
+ {
+ "idx": 18,
+ "version": "7",
+ "when": 1766613036394,
+ "tag": "0018_sour_roughhouse",
+ "breakpoints": true
+ },
+ {
+ "idx": 19,
+ "version": "7",
+ "when": 1766613085822,
+ "tag": "0019_wide_gamora",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts
index 186e960..f34ab02 100644
--- a/src/lib/server/db/schema.ts
+++ b/src/lib/server/db/schema.ts
@@ -29,6 +29,7 @@ export const user = pgTable('user', {
shopScore: real().notNull().default(0),
hasBasePrinter: boolean().notNull().default(false),
+ // bricksSpentOnUpgrades: integer().notNull().default(0),
hasT1Review: boolean().notNull().default(false), // Has access to t1 review
hasT2Review: boolean().notNull().default(false), // Has access to t2 review
@@ -203,6 +204,91 @@ export const devlog = pgTable('devlog', {
updatedAt: timestamp().notNull().defaultNow()
});
+// Market
+
+export const marketItem = pgTable('market_item', {
+ id: serial().primaryKey(),
+ createdBy: integer().references(() => user.id),
+
+ name: text().notNull(),
+ description: text().notNull(),
+ image: text().notNull(),
+
+ minRequiredShopScore: integer().notNull().default(0),
+
+ minShopScore: integer().notNull(),
+ maxShopScore: integer().notNull(), // Score after which price becomes constant
+ maxPrice: integer().notNull(),
+ minPrice: integer().notNull(),
+
+ isPublic: boolean().notNull().default(false),
+
+ deleted: boolean().notNull().default(false),
+ createdAt: timestamp().notNull().defaultNow(),
+ updatedAt: timestamp().notNull().defaultNow()
+});
+
+export const marketOrderStatus = pgEnum('market_order_status', [
+ 'awaiting_approval',
+ 'approved',
+ 'fulfilled',
+ 'denied',
+ 'refunded'
+]);
+
+export const marketItemOrder = pgTable('market_item_order', {
+ id: serial().primaryKey(),
+ userId: integer().references(() => user.id).notNull(),
+
+ addressId: text().notNull(),
+ bricksPaid: integer().notNull(),
+
+ status: marketOrderStatus().notNull().default('awaiting_approval'),
+ userNotes: text().notNull(),
+ notes: text(), // stuff like tracking code, shown to user
+
+ deleted: boolean().notNull().default(false),
+ createdAt: timestamp().notNull().defaultNow()
+});
+
+// export const marketBasePrinter = pgTable('market_base_printer', {
+// id: serial().primaryKey(),
+// createdBy: integer().references(() => user.id),
+
+// name: text().notNull(),
+// description: text().notNull(),
+// image: text().notNull(),
+
+// minRequiredShopScore: integer().notNull().default(0),
+// isPublic: boolean().notNull().default(false),
+
+// deleted: boolean().notNull().default(false),
+// createdAt: timestamp().notNull().defaultNow(),
+// updatedAt: timestamp().notNull().defaultNow()
+// });
+
+// export const marketPrinterUpgrade = pgTable('market_printer_upgrade', {
+// id: serial().primaryKey(),
+// createdBy: integer().references(() => user.id),
+
+// name: text().notNull(),
+// description: text().notNull(),
+// image: text().notNull(),
+
+// minRequiredShopScore: integer().notNull().default(0),
+
+// minShopScore: integer().notNull(),
+// maxShopScore: integer().notNull(), // Score after which price becomes constant
+// maxPrice: integer().notNull(),
+// minPrice: integer().notNull(),
+
+// isPublic: boolean().notNull().default(false),
+
+// deleted: boolean().notNull().default(false),
+// createdAt: timestamp().notNull().defaultNow(),
+// updatedAt: timestamp().notNull().defaultNow()
+// });
+
export type Session = typeof session.$inferSelect;
export type User = typeof user.$inferSelect;
export type Project = typeof project.$inferSelect;
@@ -210,3 +296,5 @@ export type Project = typeof project.$inferSelect;
export type T1Review = typeof t1Review.$inferSelect;
export type LegionReview = typeof legionReview.$inferSelect;
export type T2Review = typeof t2Review.$inferSelect;
+
+export type MarketItem = typeof marketItem.$inferSelect;
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 1677fae..d3d0eef 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -55,3 +55,26 @@ export default function fileSizeFromUrl(url: string): Promise Make sure you have a Hackatime account associated with your Hack Club Auth or Slack account. Make sure you have a Hackatime account associated with your Slack account. Stats MarketHackatime account not found
-
No public items yet.
+ {:else} +Nothing to see here.
+ {:else} ++ +
+ +
+ +
diff --git a/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.server.ts b/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.server.ts new file mode 100644 index 0000000..8a1deb9 --- /dev/null +++ b/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.server.ts @@ -0,0 +1,89 @@ +import { db } from '$lib/server/db/index.js'; +import { marketItem } from '$lib/server/db/schema.js'; +import { error, redirect } from '@sveltejs/kit'; +import type { Actions } from './$types'; +import { eq, and } from 'drizzle-orm'; + +export async function load({ locals, params }) { + if (!locals.user?.hasAdmin) { + throw error(403, { message: 'oi get out' }); + } + + const id: number = parseInt(params.id); + + const [item] = await db + .select() + .from(marketItem) + .where(and(eq(marketItem.deleted, false), eq(marketItem.id, id))); + + if (!item) { + return error(404, { message: 'item not found' }); + } + + return { + marketItem: item + }; +} + +export const actions: Actions = { + default: async ({ request, locals, params }) => { + if (!locals.user?.hasAdmin) { + throw error(403, { message: 'oi get out' }); + } + + const id: number = parseInt(params.id); + + const [item] = await db + .select() + .from(marketItem) + .where(and(eq(marketItem.deleted, false), eq(marketItem.id, id))); + + if (!item) { + return error(404, { message: 'item not found' }); + } + + const formData = await request.formData(); + const name = formData.get('name')?.toString(); + const description = formData.get('description')?.toString(); + const image = formData.get('image')?.toString(); + const minRequiredShopScore = parseInt(formData.get('minRequiredShopScore')?.toString() || '0'); + const minShopScore = parseInt(formData.get('minShopScore')?.toString() || '0'); + const maxShopScore = parseInt(formData.get('maxShopScore')?.toString() || '0'); + const minPrice = parseInt(formData.get('minPrice')?.toString() || '0'); + const maxPrice = parseInt(formData.get('maxPrice')?.toString() || '0'); + const isPublic = formData.get('isPublic') === 'on'; + + // Don't really need to implement proper validation, page is admins only + + if (!name || !description || !image) { + throw error(400, { message: 'Missing required fields' }); + } + + if (maxPrice < minPrice) { + throw error(400, { message: 'Max price must be greater than or equal to min price' }); + } + + if (maxShopScore < minShopScore) { + throw error(400, { + message: 'Max shop score must be greater than or equal to min shop score' + }); + } + + await db + .update(marketItem) + .set({ + name, + description, + image, + minRequiredShopScore, + minShopScore, + maxShopScore, + minPrice, + maxPrice, + isPublic + }) + .where(eq(marketItem.id, id)); + + return redirect(302, '/dashboard/admin/admin/market'); + } +}; diff --git a/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.svelte b/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.svelte new file mode 100644 index 0000000..aafe840 --- /dev/null +++ b/src/routes/dashboard/admin/admin/market/item/[id]/edit/+page.svelte @@ -0,0 +1,150 @@ + + +
+ +
+ +
+ +
diff --git a/src/routes/dashboard/admin/admin/market/item/create/+page.server.ts b/src/routes/dashboard/admin/admin/market/item/create/+page.server.ts new file mode 100644 index 0000000..23b2462 --- /dev/null +++ b/src/routes/dashboard/admin/admin/market/item/create/+page.server.ts @@ -0,0 +1,62 @@ +import { db } from '$lib/server/db/index.js'; +import { marketItem } from '$lib/server/db/schema.js'; +import { error, redirect } from '@sveltejs/kit'; +import type { Actions } from './$types'; + +export async function load({ locals }) { + if (!locals.user?.hasAdmin) { + throw error(403, { message: 'oi get out' }); + } + + return {}; +} + +export const actions: Actions = { + default: async ({ request, locals }) => { + if (!locals.user?.hasAdmin) { + throw error(403, { message: 'oi get out' }); + } + + const formData = await request.formData(); + const name = formData.get('name')?.toString(); + const description = formData.get('description')?.toString(); + const image = formData.get('image')?.toString(); + const minRequiredShopScore = parseInt(formData.get('minRequiredShopScore')?.toString() || '0'); + const minShopScore = parseInt(formData.get('minShopScore')?.toString() || '0'); + const maxShopScore = parseInt(formData.get('maxShopScore')?.toString() || '0'); + const minPrice = parseInt(formData.get('minPrice')?.toString() || '0'); + const maxPrice = parseInt(formData.get('maxPrice')?.toString() || '0'); + const isPublic = formData.get('isPublic') === 'on'; + + // Don't need to implement proper validation, page is admins only + + if (!name || !description || !image) { + throw error(400, { message: 'Missing required fields' }); + } + + if (maxPrice < minPrice) { + throw error(400, { message: 'Max price must be greater than or equal to min price' }); + } + + if (maxShopScore < minShopScore) { + throw error(400, { + message: 'Max shop score must be greater than or equal to min shop score' + }); + } + + await db.insert(marketItem).values({ + createdBy: locals.user.id, + name, + description, + image, + minRequiredShopScore, + minShopScore, + maxShopScore, + minPrice, + maxPrice, + isPublic + }); + + return redirect(302, '/dashboard/admin/admin/market'); + } +}; diff --git a/src/routes/dashboard/admin/admin/market/item/create/+page.svelte b/src/routes/dashboard/admin/admin/market/item/create/+page.svelte new file mode 100644 index 0000000..2bc7af8 --- /dev/null +++ b/src/routes/dashboard/admin/admin/market/item/create/+page.svelte @@ -0,0 +1,139 @@ + + +
+ +
+ +
diff --git a/src/routes/dashboard/admin/admin/stats/+page.server.ts b/src/routes/dashboard/admin/admin/stats/+page.server.ts index 2156bfe..09cbd08 100644 --- a/src/routes/dashboard/admin/admin/stats/+page.server.ts +++ b/src/routes/dashboard/admin/admin/stats/+page.server.ts @@ -8,7 +8,7 @@ export async function load({ locals }) { throw error(500); } if (!locals.user.hasAdmin) { - throw error(403, { message: 'get out, peasant' }); + throw error(403, { message: 'oi get out' }); } const [users] = await db diff --git a/src/routes/dashboard/admin/admin/users/+page.server.ts b/src/routes/dashboard/admin/admin/users/+page.server.ts index 37403cb..e728b17 100644 --- a/src/routes/dashboard/admin/admin/users/+page.server.ts +++ b/src/routes/dashboard/admin/admin/users/+page.server.ts @@ -8,7 +8,7 @@ export async function load({ locals }) { throw error(500); } if (!locals.user.hasAdmin) { - throw error(403, { message: 'get out, peasant' }); + throw error(403, { message: 'oi get out' }); } const users = await db.select().from(user); @@ -24,7 +24,7 @@ export const actions = { throw error(500); } if (!locals.user.hasAdmin) { - throw error(403, { message: 'get out, peasant' }); + throw error(403, { message: 'oi get out' }); } await db.delete(session); diff --git a/src/routes/dashboard/admin/admin/users/+page.svelte b/src/routes/dashboard/admin/admin/users/+page.svelte index 9d85401..455aab6 100644 --- a/src/routes/dashboard/admin/admin/users/+page.svelte +++ b/src/routes/dashboard/admin/admin/users/+page.svelte @@ -13,7 +13,7 @@ let logoutEveryonePending = $state(false); -
+
Loading more...
+ {/if} + + {#if loadError} +You're caught up.
+ {/if} {/if}-
+
-
+{#if data.marketItems.length === 0}
+
+ Market score: {data.user.shopScore} + (allows you to get stuff for cheaper and unlock more items!) +
- +
+{/if} diff --git a/src/routes/dashboard/market/MarketItem.svelte b/src/routes/dashboard/market/MarketItem.svelte new file mode 100644 index 0000000..992cc27 --- /dev/null +++ b/src/routes/dashboard/market/MarketItem.svelte @@ -0,0 +1,53 @@ + + +
{item.description}
+ {#if item.discountAmount > 0} +diff --git a/src/routes/dashboard/market/MarketTimer.svelte b/src/routes/dashboard/market/MarketTimer.svelte new file mode 100644 index 0000000..9aa1e6c --- /dev/null +++ b/src/routes/dashboard/market/MarketTimer.svelte @@ -0,0 +1,57 @@ + + +
\ No newline at end of file diff --git a/src/routes/dashboard/market/item/[id]/+page.server.ts b/src/routes/dashboard/market/item/[id]/+page.server.ts new file mode 100644 index 0000000..cb3d970 --- /dev/null +++ b/src/routes/dashboard/market/item/[id]/+page.server.ts @@ -0,0 +1,148 @@ +import { db } from '$lib/server/db/index.js'; +import { marketItem, marketItemOrder, user } from '$lib/server/db/schema.js'; +import { decrypt } from '$lib/server/encryption'; +import { getUserData } from '$lib/server/idvUserData'; +import { calculateMarketPrice } from '$lib/utils'; +import { error, redirect } from '@sveltejs/kit'; +import { eq, and } from 'drizzle-orm'; +import type { Actions } from './$types'; + +export async function load({ locals, params }) { + if (!locals.user) { + throw error(500); + } + + const id: number = parseInt(params.id); + + const itemWithPrice = await getItemWithPrice(id, locals); + + let userDataError = false; + let addresses = null; + + if (locals.user.idvToken) { + const token = decrypt(locals.user.idvToken); + let userData = null; + + try { + userData = await getUserData(token); + } catch { + userDataError = true; + } + + addresses = userData?.addresses; + } else { + userDataError = true; + } + + return { + marketItem: itemWithPrice, + addresses, + userDataError + }; +} + +export const actions = { + default: async ({ locals, request, params }) => { + if (!locals.user) { + throw error(500); + } + + const id: number = parseInt(params.id); + + const data = await request.formData(); + const addressId = data.get('address')?.toString(); + const notes = data.get('notes')?.toString(); + + if (!addressId) { + throw error(400, { message: 'invalid address id' }); + } + + if (notes === null || notes === undefined || notes.length > 10000) { + throw error(400, { message: 'stop writing so much in notes' }); + } + + const itemWithPrice = await getItemWithPrice(id, locals); + + const token = decrypt(locals.user.idvToken!); + let userData = null; + + try { + userData = await getUserData(token); + } catch { + throw error(403, { message: 'failed to fetch address, try logging out and back in' }); + } + + const addresses: [{ id: string | null }] | null = userData?.addresses; + + if (!addresses || !addresses.length || addresses.length <= 0) { + throw error(400, { message: 'no addresses added on auth.hackclub.com' }); + } + + const address = addresses.find((addr) => addr.id! === addressId); + + if (!address) { + throw error(400, { message: 'chosen address not found' }); + } + + // Check if user can afford + if ( + itemWithPrice.computedPrice > locals.user.brick || + itemWithPrice.minRequiredShopScore > locals.user.shopScore + ) { + throw error(403, { message: "you can't afford this" }); + } + + await db + .update(user) + .set({ + brick: locals.user.brick - itemWithPrice.computedPrice + }) + .where(eq(user.id, locals.user.id)); + + await db.insert(marketItemOrder).values({ + userId: locals.user.id, + addressId, + bricksPaid: itemWithPrice.computedPrice, + userNotes: notes + }); + + // TODO: change this to orders page + return redirect(302, '/dashboard/market'); + } +} satisfies Actions; + +async function getItemWithPrice(id: number, locals: { user: { shopScore: number } | null }) { + const [item] = await db + .select({ + id: marketItem.id, + name: marketItem.name, + description: marketItem.description, + image: marketItem.image, + minPrice: marketItem.minPrice, + maxPrice: marketItem.maxPrice, + minShopScore: marketItem.minShopScore, + maxShopScore: marketItem.maxShopScore, + minRequiredShopScore: marketItem.minRequiredShopScore + }) + .from(marketItem) + .where(and(eq(marketItem.deleted, false), eq(marketItem.isPublic, true), eq(marketItem.id, id))) + .limit(1); + + if (!item) { + throw error(404, { message: 'market item not found' }); + } + + const shopScore = locals.user!.shopScore; + const computedPrice = calculateMarketPrice( + item.minPrice, + item.maxPrice, + item.minShopScore, + item.maxShopScore, + shopScore + ); + const discountAmount = 1 - computedPrice / item.maxPrice; + + const itemWithPrice = { ...item, computedPrice, discountAmount }; + + return itemWithPrice; +} diff --git a/src/routes/dashboard/market/item/[id]/+page.svelte b/src/routes/dashboard/market/item/[id]/+page.svelte new file mode 100644 index 0000000..6263c81 --- /dev/null +++ b/src/routes/dashboard/market/item/[id]/+page.svelte @@ -0,0 +1,104 @@ + + +
+ +
+ +
It'll cost you {data.marketItem.computedPrice} bricks
+ + +diff --git a/src/routes/dashboard/users/[id]/+page.server.ts b/src/routes/dashboard/users/[id]/+page.server.ts index 9f2e2e2..eeae046 100644 --- a/src/routes/dashboard/users/[id]/+page.server.ts +++ b/src/routes/dashboard/users/[id]/+page.server.ts @@ -47,12 +47,14 @@ export async function load({ locals, params }) { slackId: requestedUser.slackId, profilePicture: requestedUser.profilePicture, name: requestedUser.name, - + isPrinter: requestedUser.isPrinter, hasT1Review: requestedUser.hasT1Review, hasT2Review: requestedUser.hasT2Review, hasAdmin: requestedUser.hasAdmin, + shopScore: requestedUser.shopScore, + createdAt: requestedUser.createdAt, lastLoginAt: requestedUser.id === locals.user?.id ? requestedUser.lastLoginAt : null }, diff --git a/src/routes/dashboard/users/[id]/+page.svelte b/src/routes/dashboard/users/[id]/+page.svelte index cba5280..14b5b27 100644 --- a/src/routes/dashboard/users/[id]/+page.svelte +++ b/src/routes/dashboard/users/[id]/+page.svelte @@ -34,6 +34,12 @@ {/if}
+
+ Market score: {data.requestedUser.shopScore} +
+