diff --git a/.vscode/settings.json b/.vscode/settings.json
index a95220c..76d6767 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -15,5 +15,9 @@
"./web/src/pages",
"./web/src/index.js",
"./web/src/Routes.js",
+ ],
+ "cSpell.words": [
+ "Uploader",
+ "redwoodjs"
]
}
diff --git a/api/prisma/migrations/20201009213512-create-posts/README.md b/api/prisma/migrations/20201009213512-create-posts/README.md
deleted file mode 100644
index f52912a..0000000
--- a/api/prisma/migrations/20201009213512-create-posts/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Migration `20201009213512-create-posts`
-
-This migration has been generated by Kurt Hutten at 10/10/2020, 8:35:12 AM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-CREATE TABLE "Post" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "title" TEXT NOT NULL,
- "body" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-)
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration ..20201009213512-create-posts
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,0 +1,18 @@
-+datasource DS {
-+ // optionally set multiple providers
-+ // example: provider = ["sqlite", "postgresql"]
-+ provider = "sqlite"
-+ url = "***"
-+}
-+
-+generator client {
-+ provider = "prisma-client-js"
-+ binaryTargets = "native"
-+}
-+
-+model Post {
-+ id Int @id @default(autoincrement())
-+ title String
-+ body String
-+ createdAt DateTime @default(now())
-+}
-```
-
-
diff --git a/api/prisma/migrations/20201009213512-create-posts/schema.prisma b/api/prisma/migrations/20201009213512-create-posts/schema.prisma
deleted file mode 100644
index 624cbdb..0000000
--- a/api/prisma/migrations/20201009213512-create-posts/schema.prisma
+++ /dev/null
@@ -1,18 +0,0 @@
-datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
diff --git a/api/prisma/migrations/20201009213512-create-posts/steps.json b/api/prisma/migrations/20201009213512-create-posts/steps.json
deleted file mode 100644
index f2edc88..0000000
--- a/api/prisma/migrations/20201009213512-create-posts/steps.json
+++ /dev/null
@@ -1,120 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "CreateSource",
- "source": "DS"
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Source",
- "source": "DS"
- },
- "argument": "provider",
- "value": "\"sqlite\""
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Source",
- "source": "DS"
- },
- "argument": "url",
- "value": "\"***\""
- },
- {
- "tag": "CreateModel",
- "model": "Post"
- },
- {
- "tag": "CreateField",
- "model": "Post",
- "field": "id",
- "type": "Int",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Post",
- "field": "id"
- },
- "directive": "id"
- }
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Post",
- "field": "id"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Post",
- "field": "id"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "autoincrement()"
- },
- {
- "tag": "CreateField",
- "model": "Post",
- "field": "title",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Post",
- "field": "body",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Post",
- "field": "createdAt",
- "type": "DateTime",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Post",
- "field": "createdAt"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Post",
- "field": "createdAt"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "now()"
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011043647-create-parts/README.md b/api/prisma/migrations/20201011043647-create-parts/README.md
deleted file mode 100644
index 1def1c5..0000000
--- a/api/prisma/migrations/20201011043647-create-parts/README.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Migration `20201011043647-create-parts`
-
-This migration has been generated by Kurt Hutten at 10/11/2020, 3:36:47 PM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-CREATE TABLE "Part" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "title" TEXT NOT NULL,
- "description" TEXT NOT NULL,
- "mainImage" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-)
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201009213512-create-posts..20201011043647-create-parts
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,9 +1,9 @@
- datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
-- url = "***"
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -15,4 +15,14 @@
- title String
- body String
- createdAt DateTime @default(now())
- }
-+
-+model Part {
-+ id Int @id @default(autoincrement())
-+ title String
-+ description String // markdown string
-+ mainImage String // link to cloudinary
-+ createdAt DateTime @default(now())
-+ // userId
-+ //likes, comments, reactions
-+}
-```
-
-
diff --git a/api/prisma/migrations/20201011043647-create-parts/schema.prisma b/api/prisma/migrations/20201011043647-create-parts/schema.prisma
deleted file mode 100644
index 6d2b834..0000000
--- a/api/prisma/migrations/20201011043647-create-parts/schema.prisma
+++ /dev/null
@@ -1,28 +0,0 @@
-datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
diff --git a/api/prisma/migrations/20201011043647-create-parts/steps.json b/api/prisma/migrations/20201011043647-create-parts/steps.json
deleted file mode 100644
index 3328ce6..0000000
--- a/api/prisma/migrations/20201011043647-create-parts/steps.json
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "CreateModel",
- "model": "Part"
- },
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "id",
- "type": "Int",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "id"
- },
- "directive": "id"
- }
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "id"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "id"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "autoincrement()"
- },
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "title",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "description",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "mainImage",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "createdAt",
- "type": "DateTime",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "createdAt"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "createdAt"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "now()"
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/README.md b/api/prisma/migrations/20201011052155-add-code-to-part/README.md
deleted file mode 100644
index ffbd7bc..0000000
--- a/api/prisma/migrations/20201011052155-add-code-to-part/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# Migration `20201011052155-add-code-to-part`
-
-This migration has been generated by Kurt Hutten at 10/11/2020, 4:21:55 PM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_Part" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "title" TEXT NOT NULL,
- "description" TEXT NOT NULL,
- "code" TEXT NOT NULL DEFAULT '// Welcome to Cascade Studio! Here are some useful functions:
-// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()
-// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()
-// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),
-// FilletEdges(), ChamferEdges(),
-// Slider(), Button(), Checkbox()
-let holeRadius = Slider("Radius", 30 , 20 , 40);
-let sphere = Sphere(50);
-let cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));
-let cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));
-
-Translate([-25, 0, 40], Text3D("Hi!"));/n// Don''t forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!',
- "mainImage" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-INSERT INTO "new_Part" ("id", "title", "description", "mainImage", "createdAt") SELECT "id", "title", "description", "mainImage", "createdAt" FROM "Part";
-DROP TABLE "Part";
-ALTER TABLE "new_Part" RENAME TO "Part";
-PRAGMA foreign_key_check;
-PRAGMA foreign_keys=ON
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201011043647-create-parts..20201011052155-add-code-to-part
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,9 +1,9 @@
- datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
-- url = "***"
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -20,8 +20,9 @@
- model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
-+ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-```
-
-
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma b/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma
deleted file mode 100644
index 41ca83b..0000000
--- a/api/prisma/migrations/20201011052155-add-code-to-part/schema.prisma
+++ /dev/null
@@ -1,29 +0,0 @@
-datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
diff --git a/api/prisma/migrations/20201011052155-add-code-to-part/steps.json b/api/prisma/migrations/20201011052155-add-code-to-part/steps.json
deleted file mode 100644
index 0c8bd6f..0000000
--- a/api/prisma/migrations/20201011052155-add-code-to-part/steps.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "CreateField",
- "model": "Part",
- "field": "code",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "code"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "code"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "\"// Welcome to Cascade Studio! Here are some useful functions:\\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\\n// FilletEdges(), ChamferEdges(),\\n// Slider(), Button(), Checkbox()\\nlet holeRadius = Slider(\\\"Radius\\\", 30 , 20 , 40);\\nlet sphere = Sphere(50);\\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\\n\\nTranslate([-25, 0, 40], Text3D(\\\"Hi!\\\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!\""
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md
deleted file mode 100644
index 1e30c97..0000000
--- a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/README.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Migration `20201011082558-add-code-not-needed-upon-create`
-
-This migration has been generated by Kurt Hutten at 10/11/2020, 7:25:58 PM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_Part" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "title" TEXT NOT NULL,
- "description" TEXT NOT NULL,
- "code" TEXT NOT NULL DEFAULT '// Welcome to Cascade Studio! Here are some useful functions:
-// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()
-// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()
-// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),
-// FilletEdges(), ChamferEdges(),
-// Slider(), Button(), Checkbox()
-let holeRadius = Slider("Radius", 30 , 20 , 40);
-let sphere = Sphere(50);
-let cylinderZ = Cylinder(holeRadius, 200, true);
-let cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));
-let cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));
-Translate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));
-
-Translate([-25, 0, 40], Text3D("Hi!"));
-// Don''t forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!',
- "mainImage" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-);
-INSERT INTO "new_Part" ("id", "title", "description", "mainImage", "createdAt", "code") SELECT "id", "title", "description", "mainImage", "createdAt", "code" FROM "Part";
-DROP TABLE "Part";
-ALTER TABLE "new_Part" RENAME TO "Part";
-PRAGMA foreign_key_check;
-PRAGMA foreign_keys=ON
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201011052155-add-code-to-part..20201011082558-add-code-not-needed-upon-create
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,9 +1,9 @@
- datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
-- url = "***"
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -20,9 +20,9 @@
- model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
-- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);/nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));/nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));/n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
-+ code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-```
-
-
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma
deleted file mode 100644
index f22b4b7..0000000
--- a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/schema.prisma
+++ /dev/null
@@ -1,29 +0,0 @@
-datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
diff --git a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json b/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json
deleted file mode 100644
index 8c127a5..0000000
--- a/api/prisma/migrations/20201011082558-add-code-not-needed-upon-create/steps.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "UpdateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Part",
- "field": "code"
- },
- "directive": "default"
- },
- "argument": "",
- "newValue": "\"// Welcome to Cascade Studio! Here are some useful functions:\\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\\n// FilletEdges(), ChamferEdges(),\\n// Slider(), Button(), Checkbox()\\nlet holeRadius = Slider(\\\"Radius\\\", 30 , 20 , 40);\\nlet sphere = Sphere(50);\\nlet cylinderZ = Cylinder(holeRadius, 200, true);\\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\\n\\nTranslate([-25, 0, 40], Text3D(\\\"Hi!\\\"));\\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!\""
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201011095227-create-contact/README.md b/api/prisma/migrations/20201011095227-create-contact/README.md
deleted file mode 100644
index 5748d5e..0000000
--- a/api/prisma/migrations/20201011095227-create-contact/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Migration `20201011095227-create-contact`
-
-This migration has been generated by Kurt Hutten at 10/11/2020, 8:52:27 PM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-CREATE TABLE "Contact" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "name" TEXT NOT NULL,
- "email" TEXT NOT NULL,
- "message" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
-)
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201011082558-add-code-not-needed-upon-create..20201011095227-create-contact
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,9 +1,9 @@
- datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
-- url = "***"
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -26,4 +26,12 @@
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
- }
-+
-+model Contact {
-+ id Int @id @default(autoincrement())
-+ name String
-+ email String
-+ message String
-+ createdAt DateTime @default(now())
-+}
-```
-
-
diff --git a/api/prisma/migrations/20201011095227-create-contact/schema.prisma b/api/prisma/migrations/20201011095227-create-contact/schema.prisma
deleted file mode 100644
index 03189f2..0000000
--- a/api/prisma/migrations/20201011095227-create-contact/schema.prisma
+++ /dev/null
@@ -1,37 +0,0 @@
-datasource DS {
- // optionally set multiple providers
- // example: provider = ["sqlite", "postgresql"]
- provider = "sqlite"
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
-
-model Contact {
- id Int @id @default(autoincrement())
- name String
- email String
- message String
- createdAt DateTime @default(now())
-}
diff --git a/api/prisma/migrations/20201011095227-create-contact/steps.json b/api/prisma/migrations/20201011095227-create-contact/steps.json
deleted file mode 100644
index 0ca4b72..0000000
--- a/api/prisma/migrations/20201011095227-create-contact/steps.json
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "CreateModel",
- "model": "Contact"
- },
- {
- "tag": "CreateField",
- "model": "Contact",
- "field": "id",
- "type": "Int",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Contact",
- "field": "id"
- },
- "directive": "id"
- }
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Contact",
- "field": "id"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Contact",
- "field": "id"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "autoincrement()"
- },
- {
- "tag": "CreateField",
- "model": "Contact",
- "field": "name",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Contact",
- "field": "email",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Contact",
- "field": "message",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateField",
- "model": "Contact",
- "field": "createdAt",
- "type": "DateTime",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "Contact",
- "field": "createdAt"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "Contact",
- "field": "createdAt"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "now()"
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201018233330-add-simple-user-model/README.md b/api/prisma/migrations/20201018233330-add-simple-user-model/README.md
deleted file mode 100644
index c8ec755..0000000
--- a/api/prisma/migrations/20201018233330-add-simple-user-model/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# Migration `20201018233330-add-simple-user-model`
-
-This migration has been generated by Kurt Hutten at 10/19/2020, 10:33:30 AM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-CREATE TABLE "User" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "userName" TEXT NOT NULL,
- "email" TEXT NOT NULL,
- "issuer" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- "image" TEXT,
- "bio" TEXT
-)
-
-CREATE UNIQUE INDEX "User.userName_unique" ON "User"("userName")
-
-CREATE UNIQUE INDEX "User.email_unique" ON "User"("email")
-
-CREATE UNIQUE INDEX "User.issuer_unique" ON "User"("issuer")
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201011095227-create-contact..20201018233330-add-simple-user-model
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,9 +1,7 @@
- datasource DS {
-- // optionally set multiple providers
-- // example: provider = ["sqlite", "postgresql"]
-- provider = "sqlite"
-- url = "***"
-+ provider = ["sqlite", "postgresql"]
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -34,4 +32,17 @@
- email String
- message String
- createdAt DateTime @default(now())
- }
-+
-+model User {
-+ id Int @id @default(autoincrement())
-+ userName String @unique
-+ email String @unique
-+ issuer String @unique
-+
-+ createdAt DateTime @default(now())
-+ updatedAt DateTime @updatedAt
-+
-+ image String? // url maybe id or file storage service? cloudinary?
-+ bio String? //mark down
-+}
-```
-
-
diff --git a/api/prisma/migrations/20201018233330-add-simple-user-model/schema.prisma b/api/prisma/migrations/20201018233330-add-simple-user-model/schema.prisma
deleted file mode 100644
index 15e3468..0000000
--- a/api/prisma/migrations/20201018233330-add-simple-user-model/schema.prisma
+++ /dev/null
@@ -1,48 +0,0 @@
-datasource DS {
- provider = ["sqlite", "postgresql"]
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
-
-model Contact {
- id Int @id @default(autoincrement())
- name String
- email String
- message String
- createdAt DateTime @default(now())
-}
-
-model User {
- id Int @id @default(autoincrement())
- userName String @unique
- email String @unique
- issuer String @unique
-
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- image String? // url maybe id or file storage service? cloudinary?
- bio String? //mark down
-}
diff --git a/api/prisma/migrations/20201018233330-add-simple-user-model/steps.json b/api/prisma/migrations/20201018233330-add-simple-user-model/steps.json
deleted file mode 100644
index 8ea741d..0000000
--- a/api/prisma/migrations/20201018233330-add-simple-user-model/steps.json
+++ /dev/null
@@ -1,179 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "UpdateArgument",
- "location": {
- "tag": "Source",
- "source": "DS"
- },
- "argument": "provider",
- "newValue": "[\"sqlite\", \"postgresql\"]"
- },
- {
- "tag": "CreateModel",
- "model": "User"
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "id",
- "type": "Int",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "id"
- },
- "directive": "id"
- }
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "id"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "id"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "autoincrement()"
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "userName",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "userName"
- },
- "directive": "unique"
- }
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "email",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "email"
- },
- "directive": "unique"
- }
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "issuer",
- "type": "String",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "issuer"
- },
- "directive": "unique"
- }
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "createdAt",
- "type": "DateTime",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "createdAt"
- },
- "directive": "default"
- }
- },
- {
- "tag": "CreateArgument",
- "location": {
- "tag": "Directive",
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "createdAt"
- },
- "directive": "default"
- },
- "argument": "",
- "value": "now()"
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "updatedAt",
- "type": "DateTime",
- "arity": "Required"
- },
- {
- "tag": "CreateDirective",
- "location": {
- "path": {
- "tag": "Field",
- "model": "User",
- "field": "updatedAt"
- },
- "directive": "updatedAt"
- }
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "image",
- "type": "String",
- "arity": "Optional"
- },
- {
- "tag": "CreateField",
- "model": "User",
- "field": "bio",
- "type": "String",
- "arity": "Optional"
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201019072122-add-simplify-user-model/README.md b/api/prisma/migrations/20201019072122-add-simplify-user-model/README.md
deleted file mode 100644
index 29d4e11..0000000
--- a/api/prisma/migrations/20201019072122-add-simplify-user-model/README.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Migration `20201019072122-add-simplify-user-model`
-
-This migration has been generated by Kurt Hutten at 10/19/2020, 6:21:22 PM.
-You can check out the [state of the schema](./schema.prisma) after the migration.
-
-## Database Steps
-
-```sql
-DROP INDEX "User.issuer_unique"
-
-DROP INDEX "User.userName_unique"
-
-PRAGMA foreign_keys=OFF;
-CREATE TABLE "new_User" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "email" TEXT NOT NULL,
- "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "updatedAt" DATETIME NOT NULL,
- "image" TEXT,
- "bio" TEXT
-);
-INSERT INTO "new_User" ("id", "email", "createdAt", "updatedAt", "image", "bio") SELECT "id", "email", "createdAt", "updatedAt", "image", "bio" FROM "User";
-DROP TABLE "User";
-ALTER TABLE "new_User" RENAME TO "User";
-CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");
-PRAGMA foreign_key_check;
-PRAGMA foreign_keys=ON
-```
-
-## Changes
-
-```diff
-diff --git schema.prisma schema.prisma
-migration 20201018233330-add-simple-user-model..20201019072122-add-simplify-user-model
---- datamodel.dml
-+++ datamodel.dml
-@@ -1,7 +1,7 @@
- datasource DS {
- provider = ["sqlite", "postgresql"]
-- url = "***"
-+ url = "***"
- }
- generator client {
- provider = "prisma-client-js"
-@@ -34,12 +34,12 @@
- createdAt DateTime @default(now())
- }
- model User {
-- id Int @id @default(autoincrement())
-- userName String @unique
-- email String @unique
-- issuer String @unique
-+ id Int @id @default(autoincrement())
-+ email String @unique
-+ // userName String @unique
-+ // issuer String @unique
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-```
-
-
diff --git a/api/prisma/migrations/20201019072122-add-simplify-user-model/schema.prisma b/api/prisma/migrations/20201019072122-add-simplify-user-model/schema.prisma
deleted file mode 100644
index 24140d8..0000000
--- a/api/prisma/migrations/20201019072122-add-simplify-user-model/schema.prisma
+++ /dev/null
@@ -1,48 +0,0 @@
-datasource DS {
- provider = ["sqlite", "postgresql"]
- url = "***"
-}
-
-generator client {
- provider = "prisma-client-js"
- binaryTargets = "native"
-}
-
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
-
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
-
-model Contact {
- id Int @id @default(autoincrement())
- name String
- email String
- message String
- createdAt DateTime @default(now())
-}
-
-model User {
- id Int @id @default(autoincrement())
- email String @unique
- // userName String @unique
- // issuer String @unique
-
- createdAt DateTime @default(now())
- updatedAt DateTime @updatedAt
-
- image String? // url maybe id or file storage service? cloudinary?
- bio String? //mark down
-}
diff --git a/api/prisma/migrations/20201019072122-add-simplify-user-model/steps.json b/api/prisma/migrations/20201019072122-add-simplify-user-model/steps.json
deleted file mode 100644
index 0285263..0000000
--- a/api/prisma/migrations/20201019072122-add-simplify-user-model/steps.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "version": "0.3.14-fixed",
- "steps": [
- {
- "tag": "DeleteField",
- "model": "User",
- "field": "userName"
- },
- {
- "tag": "DeleteField",
- "model": "User",
- "field": "issuer"
- }
- ]
-}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201101183848-db-init/README.md b/api/prisma/migrations/20201101183848-db-init/README.md
new file mode 100644
index 0000000..29cd885
--- /dev/null
+++ b/api/prisma/migrations/20201101183848-db-init/README.md
@@ -0,0 +1,158 @@
+# Migration `20201101183848-db-init`
+
+This migration has been generated by Kurt Hutten at 11/2/2020, 5:38:48 AM.
+You can check out the [state of the schema](./schema.prisma) after the migration.
+
+## Database Steps
+
+```sql
+CREATE TABLE "User" (
+ "id" TEXT NOT NULL,
+ "userName" TEXT NOT NULL,
+ "email" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "image" TEXT,
+ "bio" TEXT,
+PRIMARY KEY ("id")
+)
+
+CREATE TABLE "Part" (
+ "id" TEXT NOT NULL,
+ "title" TEXT NOT NULL,
+ "description" TEXT,
+ "code" TEXT,
+ "mainImage" TEXT,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+ "userId" TEXT NOT NULL,
+
+ FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE,
+PRIMARY KEY ("id")
+)
+
+CREATE TABLE "PartReaction" (
+ "id" TEXT NOT NULL,
+ "emote" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "partId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+
+ FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("partId") REFERENCES "Part"("id") ON DELETE CASCADE ON UPDATE CASCADE,
+PRIMARY KEY ("id")
+)
+
+CREATE TABLE "Comment" (
+ "id" TEXT NOT NULL,
+ "text" TEXT NOT NULL,
+ "userId" TEXT NOT NULL,
+ "partId" TEXT NOT NULL,
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ "updatedAt" DATETIME NOT NULL,
+
+ FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("partId") REFERENCES "Part"("id") ON DELETE CASCADE ON UPDATE CASCADE,
+PRIMARY KEY ("id")
+)
+
+CREATE UNIQUE INDEX "User.userName_unique" ON "User"("userName")
+
+CREATE UNIQUE INDEX "User.email_unique" ON "User"("email")
+
+CREATE UNIQUE INDEX "Part.title_userId_unique" ON "Part"("title", "userId")
+
+CREATE UNIQUE INDEX "PartReaction.emote_userId_partId_unique" ON "PartReaction"("emote", "userId", "partId")
+```
+
+## Changes
+
+```diff
+diff --git schema.prisma schema.prisma
+migration ..20201101183848-db-init
+--- datamodel.dml
++++ datamodel.dml
+@@ -1,0 +1,79 @@
++datasource DS {
++ provider = ["sqlite", "postgresql"]
++ url = "***"
++}
++
++generator client {
++ provider = "prisma-client-js"
++ binaryTargets = "native"
++}
++
++// sqlLight does not suport enums so we can't use enums until we set up postgresql in dev mode
++// enum Role {
++// USER
++// ADMIN
++// }
++
++// enum PartType {
++// CASCADESTUDIO
++// JSCAD
++// }
++
++model User {
++ id String @id @default(uuid())
++ userName String @unique // reffered to as userId in @relations
++ email String @unique
++ // role should probably be a list [] and also use enums, neither are supported by sqllight, so we need to set up postgresql in dev
++ // maybe let netlify handle roles for now.
++ // role String @default("user")
++
++ createdAt DateTime @default(now())
++ updatedAt DateTime @updatedAt
++
++ image String? // url maybe id or file storage service? cloudinary?
++ bio String? //mark down
++ Part Part[]
++ Reaction PartReaction[]
++ Comment Comment[]
++}
++
++model Part {
++ id String @id @default(uuid())
++ title String
++ description String? // markdown string
++ code String?
++ mainImage String? // link to cloudinary
++ createdAt DateTime @default(now())
++ updatedAt DateTime @updatedAt
++ user User @relation(fields: [userId], references: [id])
++ userId String
++
++ Comment Comment[]
++ Reaction PartReaction[]
++ @@unique([title, userId])
++}
++
++model PartReaction {
++ id String @id @default(uuid())
++ emote String // an emoji
++ user User @relation(fields: [userId], references: [id])
++ userId String
++ part Part @relation(fields: [partId], references: [id])
++ partId String
++
++ createdAt DateTime @default(now())
++ updatedAt DateTime @updatedAt
++ @@unique([emote, userId, partId])
++}
++
++model Comment {
++ id String @id @default(uuid())
++ text String // the comment, should I allow mark down?
++ user User @relation(fields: [userId], references: [id])
++ userId String
++ part Part @relation(fields: [partId], references: [id])
++ partId String
++
++ createdAt DateTime @default(now())
++ updatedAt DateTime @updatedAt
++}
+```
+
+
diff --git a/api/prisma/migrations/20201101183848-db-init/schema.prisma b/api/prisma/migrations/20201101183848-db-init/schema.prisma
new file mode 100644
index 0000000..f5d13ba
--- /dev/null
+++ b/api/prisma/migrations/20201101183848-db-init/schema.prisma
@@ -0,0 +1,79 @@
+datasource DS {
+ provider = ["sqlite", "postgresql"]
+ url = "***"
+}
+
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = "native"
+}
+
+// sqlLight does not suport enums so we can't use enums until we set up postgresql in dev mode
+// enum Role {
+// USER
+// ADMIN
+// }
+
+// enum PartType {
+// CASCADESTUDIO
+// JSCAD
+// }
+
+model User {
+ id String @id @default(uuid())
+ userName String @unique // reffered to as userId in @relations
+ email String @unique
+ // role should probably be a list [] and also use enums, neither are supported by sqllight, so we need to set up postgresql in dev
+ // maybe let netlify handle roles for now.
+ // role String @default("user")
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ image String? // url maybe id or file storage service? cloudinary?
+ bio String? //mark down
+ Part Part[]
+ Reaction PartReaction[]
+ Comment Comment[]
+}
+
+model Part {
+ id String @id @default(uuid())
+ title String
+ description String? // markdown string
+ code String?
+ mainImage String? // link to cloudinary
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ user User @relation(fields: [userId], references: [id])
+ userId String
+
+ Comment Comment[]
+ Reaction PartReaction[]
+ @@unique([title, userId])
+}
+
+model PartReaction {
+ id String @id @default(uuid())
+ emote String // an emoji
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ @@unique([emote, userId, partId])
+}
+
+model Comment {
+ id String @id @default(uuid())
+ text String // the comment, should I allow mark down?
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
diff --git a/api/prisma/migrations/20201101183848-db-init/steps.json b/api/prisma/migrations/20201101183848-db-init/steps.json
new file mode 100644
index 0000000..ce0e48a
--- /dev/null
+++ b/api/prisma/migrations/20201101183848-db-init/steps.json
@@ -0,0 +1,839 @@
+{
+ "version": "0.3.14-fixed",
+ "steps": [
+ {
+ "tag": "CreateSource",
+ "source": "DS"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Source",
+ "source": "DS"
+ },
+ "argument": "provider",
+ "value": "[\"sqlite\", \"postgresql\"]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Source",
+ "source": "DS"
+ },
+ "argument": "url",
+ "value": "\"***\""
+ },
+ {
+ "tag": "CreateModel",
+ "model": "User"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "id",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "id"
+ },
+ "directive": "id"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "id"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "id"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "uuid()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "userName",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "userName"
+ },
+ "directive": "unique"
+ }
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "email",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "email"
+ },
+ "directive": "unique"
+ }
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "createdAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "now()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "updatedAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "User",
+ "field": "updatedAt"
+ },
+ "directive": "updatedAt"
+ }
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "image",
+ "type": "String",
+ "arity": "Optional"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "bio",
+ "type": "String",
+ "arity": "Optional"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "Part",
+ "type": "Part",
+ "arity": "List"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "Reaction",
+ "type": "PartReaction",
+ "arity": "List"
+ },
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "Comment",
+ "type": "Comment",
+ "arity": "List"
+ },
+ {
+ "tag": "CreateModel",
+ "model": "Part"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "id",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "id"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "id"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "uuid()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "title",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "description",
+ "type": "String",
+ "arity": "Optional"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "code",
+ "type": "String",
+ "arity": "Optional"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "mainImage",
+ "type": "String",
+ "arity": "Optional"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "createdAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "now()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "updatedAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "updatedAt"
+ },
+ "directive": "updatedAt"
+ }
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "user",
+ "type": "User",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "user"
+ },
+ "directive": "relation"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "fields",
+ "value": "[userId]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Part",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "references",
+ "value": "[id]"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "userId",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "Comment",
+ "type": "Comment",
+ "arity": "List"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Part",
+ "field": "Reaction",
+ "type": "PartReaction",
+ "arity": "List"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Model",
+ "model": "Part",
+ "arguments": [
+ {
+ "name": "",
+ "value": "[title, userId]"
+ }
+ ]
+ },
+ "directive": "unique"
+ }
+ },
+ {
+ "tag": "CreateModel",
+ "model": "PartReaction"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "id",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "id"
+ },
+ "directive": "id"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "id"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "id"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "uuid()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "emote",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "user",
+ "type": "User",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "user"
+ },
+ "directive": "relation"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "fields",
+ "value": "[userId]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "references",
+ "value": "[id]"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "userId",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "part",
+ "type": "Part",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "part"
+ },
+ "directive": "relation"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "part"
+ },
+ "directive": "relation"
+ },
+ "argument": "fields",
+ "value": "[partId]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "part"
+ },
+ "directive": "relation"
+ },
+ "argument": "references",
+ "value": "[id]"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "partId",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "createdAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "now()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "PartReaction",
+ "field": "updatedAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "PartReaction",
+ "field": "updatedAt"
+ },
+ "directive": "updatedAt"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Model",
+ "model": "PartReaction",
+ "arguments": [
+ {
+ "name": "",
+ "value": "[emote, userId, partId]"
+ }
+ ]
+ },
+ "directive": "unique"
+ }
+ },
+ {
+ "tag": "CreateModel",
+ "model": "Comment"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "id",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "id"
+ },
+ "directive": "id"
+ }
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "id"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "id"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "uuid()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "text",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "user",
+ "type": "User",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "user"
+ },
+ "directive": "relation"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "fields",
+ "value": "[userId]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "user"
+ },
+ "directive": "relation"
+ },
+ "argument": "references",
+ "value": "[id]"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "userId",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "part",
+ "type": "Part",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "part"
+ },
+ "directive": "relation"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "part"
+ },
+ "directive": "relation"
+ },
+ "argument": "fields",
+ "value": "[partId]"
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "part"
+ },
+ "directive": "relation"
+ },
+ "argument": "references",
+ "value": "[id]"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "partId",
+ "type": "String",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "createdAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ }
+ },
+ {
+ "tag": "CreateArgument",
+ "location": {
+ "tag": "Directive",
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "createdAt"
+ },
+ "directive": "default"
+ },
+ "argument": "",
+ "value": "now()"
+ },
+ {
+ "tag": "CreateField",
+ "model": "Comment",
+ "field": "updatedAt",
+ "type": "DateTime",
+ "arity": "Required"
+ },
+ {
+ "tag": "CreateDirective",
+ "location": {
+ "path": {
+ "tag": "Field",
+ "model": "Comment",
+ "field": "updatedAt"
+ },
+ "directive": "updatedAt"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/prisma/migrations/20201105184423-add-name-to-user/README.md b/api/prisma/migrations/20201105184423-add-name-to-user/README.md
new file mode 100644
index 0000000..e89ab99
--- /dev/null
+++ b/api/prisma/migrations/20201105184423-add-name-to-user/README.md
@@ -0,0 +1,43 @@
+# Migration `20201105184423-add-name-to-user`
+
+This migration has been generated by Kurt Hutten at 11/6/2020, 5:44:24 AM.
+You can check out the [state of the schema](./schema.prisma) after the migration.
+
+## Database Steps
+
+```sql
+ALTER TABLE "User" ADD COLUMN "name" TEXT
+```
+
+## Changes
+
+```diff
+diff --git schema.prisma schema.prisma
+migration 20201101183848-db-init..20201105184423-add-name-to-user
+--- datamodel.dml
++++ datamodel.dml
+@@ -1,7 +1,7 @@
+ datasource DS {
+ provider = ["sqlite", "postgresql"]
+- url = "***"
++ url = "***"
+ }
+ generator client {
+ provider = "prisma-client-js"
+@@ -19,11 +19,12 @@
+ // JSCAD
+ // }
+ model User {
+- id String @id @default(uuid())
+- userName String @unique // reffered to as userId in @relations
+- email String @unique
++ id String @id @default(uuid())
++ userName String @unique // reffered to as userId in @relations
++ email String @unique
++ name String?
+ // role should probably be a list [] and also use enums, neither are supported by sqllight, so we need to set up postgresql in dev
+ // maybe let netlify handle roles for now.
+ // role String @default("user")
+```
+
+
diff --git a/api/prisma/migrations/20201105184423-add-name-to-user/schema.prisma b/api/prisma/migrations/20201105184423-add-name-to-user/schema.prisma
new file mode 100644
index 0000000..e0f3879
--- /dev/null
+++ b/api/prisma/migrations/20201105184423-add-name-to-user/schema.prisma
@@ -0,0 +1,80 @@
+datasource DS {
+ provider = ["sqlite", "postgresql"]
+ url = "***"
+}
+
+generator client {
+ provider = "prisma-client-js"
+ binaryTargets = "native"
+}
+
+// sqlLight does not suport enums so we can't use enums until we set up postgresql in dev mode
+// enum Role {
+// USER
+// ADMIN
+// }
+
+// enum PartType {
+// CASCADESTUDIO
+// JSCAD
+// }
+
+model User {
+ id String @id @default(uuid())
+ userName String @unique // reffered to as userId in @relations
+ email String @unique
+ name String?
+ // role should probably be a list [] and also use enums, neither are supported by sqllight, so we need to set up postgresql in dev
+ // maybe let netlify handle roles for now.
+ // role String @default("user")
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+
+ image String? // url maybe id or file storage service? cloudinary?
+ bio String? //mark down
+ Part Part[]
+ Reaction PartReaction[]
+ Comment Comment[]
+}
+
+model Part {
+ id String @id @default(uuid())
+ title String
+ description String? // markdown string
+ code String?
+ mainImage String? // link to cloudinary
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ user User @relation(fields: [userId], references: [id])
+ userId String
+
+ Comment Comment[]
+ Reaction PartReaction[]
+ @@unique([title, userId])
+}
+
+model PartReaction {
+ id String @id @default(uuid())
+ emote String // an emoji
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ @@unique([emote, userId, partId])
+}
+
+model Comment {
+ id String @id @default(uuid())
+ text String // the comment, should I allow mark down?
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+}
diff --git a/api/prisma/migrations/20201105184423-add-name-to-user/steps.json b/api/prisma/migrations/20201105184423-add-name-to-user/steps.json
new file mode 100644
index 0000000..21ac63d
--- /dev/null
+++ b/api/prisma/migrations/20201105184423-add-name-to-user/steps.json
@@ -0,0 +1,12 @@
+{
+ "version": "0.3.14-fixed",
+ "steps": [
+ {
+ "tag": "CreateField",
+ "model": "User",
+ "field": "name",
+ "type": "String",
+ "arity": "Optional"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/api/prisma/migrations/migrate.lock b/api/prisma/migrations/migrate.lock
index dddc03e..0f07957 100644
--- a/api/prisma/migrations/migrate.lock
+++ b/api/prisma/migrations/migrate.lock
@@ -1,9 +1,4 @@
# Prisma Migrate lockfile v1
-20201009213512-create-posts
-20201011043647-create-parts
-20201011052155-add-code-to-part
-20201011082558-add-code-not-needed-upon-create
-20201011095227-create-contact
-20201018233330-add-simple-user-model
-20201019072122-add-simplify-user-model
\ No newline at end of file
+20201101183848-db-init
+20201105184423-add-name-to-user
\ No newline at end of file
diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma
index baecb2a..c55ce7f 100644
--- a/api/prisma/schema.prisma
+++ b/api/prisma/schema.prisma
@@ -8,41 +8,73 @@ generator client {
binaryTargets = "native"
}
-model Post {
- id Int @id @default(autoincrement())
- title String
- body String
- createdAt DateTime @default(now())
-}
+// sqlLight does not suport enums so we can't use enums until we set up postgresql in dev mode
+// enum Role {
+// USER
+// ADMIN
+// }
-model Part {
- id Int @id @default(autoincrement())
- title String
- description String // markdown string
- code String @default("// Welcome to Cascade Studio! Here are some useful functions:\n// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()\n// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()\n// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),\n// FilletEdges(), ChamferEdges(),\n// Slider(), Button(), Checkbox()\nlet holeRadius = Slider(\"Radius\", 30 , 20 , 40);\nlet sphere = Sphere(50);\nlet cylinderZ = Cylinder(holeRadius, 200, true);\nlet cylinderY = Rotate([0,1,0], 90, Cylinder(holeRadius, 200, true));\nlet cylinderX = Rotate([1,0,0], 90, Cylinder(holeRadius, 200, true));\nTranslate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));\n\nTranslate([-25, 0, 40], Text3D(\"Hi!\"));\n// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!")
- mainImage String // link to cloudinary
- createdAt DateTime @default(now())
- // userId
- //likes, comments, reactions
-}
-
-model Contact {
- id Int @id @default(autoincrement())
- name String
- email String
- message String
- createdAt DateTime @default(now())
-}
+// enum PartType {
+// CASCADESTUDIO
+// JSCAD
+// }
model User {
- id Int @id @default(autoincrement())
- email String @unique
- // userName String @unique
- // issuer String @unique
+ id String @id @default(uuid())
+ userName String @unique // reffered to as userId in @relations
+ email String @unique
+ name String?
+ // role should probably be a list [] and also use enums, neither are supported by sqllight, so we need to set up postgresql in dev
+ // maybe let netlify handle roles for now.
+ // role String @default("user")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
- image String? // url maybe id or file storage service? cloudinary?
- bio String? //mark down
+ image String? // url maybe id or file storage service? cloudinary?
+ bio String? //mark down
+ Part Part[]
+ Reaction PartReaction[]
+ Comment Comment[]
+}
+
+model Part {
+ id String @id @default(uuid())
+ title String
+ description String? // markdown string
+ code String?
+ mainImage String? // link to cloudinary
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ user User @relation(fields: [userId], references: [id])
+ userId String
+
+ Comment Comment[]
+ Reaction PartReaction[]
+ @@unique([title, userId])
+}
+
+model PartReaction {
+ id String @id @default(uuid())
+ emote String // an emoji
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
+ @@unique([emote, userId, partId])
+}
+
+model Comment {
+ id String @id @default(uuid())
+ text String // the comment, should I allow mark down?
+ user User @relation(fields: [userId], references: [id])
+ userId String
+ part Part @relation(fields: [partId], references: [id])
+ partId String
+
+ createdAt DateTime @default(now())
+ updatedAt DateTime @updatedAt
}
diff --git a/api/src/functions/identity-signup.js b/api/src/functions/identity-signup.js
index 6b52938..1d0a003 100644
--- a/api/src/functions/identity-signup.js
+++ b/api/src/functions/identity-signup.js
@@ -1,4 +1,5 @@
import { createUserInsecure } from 'src/services/users/users.js'
+import { db } from 'src/lib/db'
export const handler = async (req, _context) => {
const body = JSON.parse(req.body)
@@ -61,10 +62,25 @@ export const handler = async (req, _context) => {
// image: '',
// bio: ''
// }
+
+ const generateUniqueUserName = async (seed, count = 0) => {
+ const isUnique = !(await db.user.findOne({
+ where: { userName: seed },
+ }))
+ if(isUnique) {
+ return seed
+ }
+ count += 1
+ const newSeed = count === 1 ? `${seed}_${count}` : seed.slice(0,-1) + count
+ return generateUniqueUserName(newSeed, count)
+ }
+ const userNameSeed = email.split('@')[0]
+ const userName = await generateUniqueUserName(userNameSeed) // TODO maybe come up with a better default userName?
const input = {
email,
- bio: 'default bio'
- // full_name: user.user_metadata.full_name
+ userName,
+ name: user.user_metadata && user.user_metadata.full_name,
+ id: user.id,
}
await createUserInsecure({input})
diff --git a/api/src/graphql/comments.sdl.js b/api/src/graphql/comments.sdl.js
new file mode 100644
index 0000000..b36296b
--- /dev/null
+++ b/api/src/graphql/comments.sdl.js
@@ -0,0 +1,35 @@
+export const schema = gql`
+ type Comment {
+ id: String!
+ text: String!
+ user: User!
+ userId: String!
+ part: Part!
+ partId: String!
+ createdAt: DateTime!
+ updatedAt: DateTime!
+ }
+
+ type Query {
+ comments: [Comment!]!
+ comment(id: String!): Comment
+ }
+
+ input CreateCommentInput {
+ text: String!
+ userId: String!
+ partId: String!
+ }
+
+ input UpdateCommentInput {
+ text: String
+ userId: String
+ partId: String
+ }
+
+ type Mutation {
+ createComment(input: CreateCommentInput!): Comment!
+ updateComment(id: String!, input: UpdateCommentInput!): Comment!
+ deleteComment(id: String!): Comment!
+ }
+`
diff --git a/api/src/graphql/contacts.sdl.js b/api/src/graphql/contacts.sdl.js
deleted file mode 100644
index c4153b6..0000000
--- a/api/src/graphql/contacts.sdl.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export const schema = gql`
- type Contact {
- id: Int!
- name: String!
- email: String!
- message: String!
- createdAt: DateTime!
- }
-
- type Query {
- contacts: [Contact!]!
- }
-
- input CreateContactInput {
- name: String!
- email: String!
- message: String!
- }
-
- input UpdateContactInput {
- name: String
- email: String
- message: String
- }
-
- type Mutation {
- createContact(input: CreateContactInput!): Contact
- }
-`
diff --git a/api/src/graphql/partReactions.sdl.js b/api/src/graphql/partReactions.sdl.js
new file mode 100644
index 0000000..4eaaa26
--- /dev/null
+++ b/api/src/graphql/partReactions.sdl.js
@@ -0,0 +1,38 @@
+export const schema = gql`
+ type PartReaction {
+ id: String!
+ emote: String!
+ user: User!
+ userId: String!
+ part: Part!
+ partId: String!
+ createdAt: DateTime!
+ updatedAt: DateTime!
+ }
+
+ type Query {
+ partReactions: [PartReaction!]!
+ partReaction(id: String!): PartReaction
+ }
+
+ input TogglePartReactionInput {
+ emote: String!
+ userId: String!
+ partId: String!
+ }
+
+ input UpdatePartReactionInput {
+ emote: String
+ userId: String
+ partId: String
+ }
+
+ type Mutation {
+ togglePartReaction(input: TogglePartReactionInput!): PartReaction!
+ updatePartReaction(
+ id: String!
+ input: UpdatePartReactionInput!
+ ): PartReaction!
+ deletePartReaction(id: String!): PartReaction!
+ }
+`
diff --git a/api/src/graphql/parts.sdl.js b/api/src/graphql/parts.sdl.js
index bec69fa..a7f42e4 100644
--- a/api/src/graphql/parts.sdl.js
+++ b/api/src/graphql/parts.sdl.js
@@ -1,23 +1,30 @@
export const schema = gql`
type Part {
- id: Int!
+ id: String!
title: String!
- description: String!
- code: String!
- mainImage: String!
+ description: String
+ code: String
+ mainImage: String
createdAt: DateTime!
+ updatedAt: DateTime!
+ user: User!
+ userId: String!
+ Comment: [Comment]!
+ Reaction(userId: String): [PartReaction]!
}
type Query {
parts: [Part!]!
- part(id: Int!): Part
+ part(id: String!): Part
+ partByUserAndTitle(userName: String! partTitle: String!): Part
}
input CreatePartInput {
title: String!
- description: String!
+ description: String
code: String
mainImage: String
+ userId: String!
}
input UpdatePartInput {
@@ -25,11 +32,12 @@ export const schema = gql`
description: String
code: String
mainImage: String
+ userId: String
}
type Mutation {
createPart(input: CreatePartInput!): Part!
- updatePart(id: Int!, input: UpdatePartInput!): Part!
- deletePart(id: Int!): Part!
+ updatePart(id: String!, input: UpdatePartInput!): Part!
+ deletePart(id: String!): Part!
}
`
diff --git a/api/src/graphql/posts.sdl.js b/api/src/graphql/posts.sdl.js
deleted file mode 100644
index ad384ff..0000000
--- a/api/src/graphql/posts.sdl.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export const schema = gql`
- type Post {
- id: Int!
- title: String!
- body: String!
- createdAt: DateTime!
- }
-
- type Query {
- posts: [Post!]!
- post(id: Int!): Post
- }
-
- input CreatePostInput {
- title: String!
- body: String!
- }
-
- input UpdatePostInput {
- title: String
- body: String
- }
-
- type Mutation {
- createPost(input: CreatePostInput!): Post!
- updatePost(id: Int!, input: UpdatePostInput!): Post!
- deletePost(id: Int!): Post!
- }
-`
diff --git a/api/src/graphql/users.sdl.js b/api/src/graphql/users.sdl.js
index 366075d..1830193 100644
--- a/api/src/graphql/users.sdl.js
+++ b/api/src/graphql/users.sdl.js
@@ -1,35 +1,45 @@
export const schema = gql`
type User {
- id: Int!
+ id: String!
+ userName: String!
email: String!
+ name: String
createdAt: DateTime!
updatedAt: DateTime!
image: String
bio: String
+ Parts: [Part]!
+ Part(partTitle: String): Part
+ Reaction: [PartReaction]!
+ Comment: [Comment]!
}
type Query {
users: [User!]!
- user(id: Int!): User
+ user(id: String!): User
+ userName(userName: String!): User
}
input CreateUserInput {
+ userName: String!
email: String!
- # issuer: String!
+ name: String
image: String
bio: String
}
input UpdateUserInput {
+ userName: String
email: String
- # issuer: String
+ name: String
image: String
bio: String
}
type Mutation {
createUser(input: CreateUserInput!): User!
- updateUser(id: Int!, input: UpdateUserInput!): User!
- deleteUser(id: Int!): User!
+ updateUser(id: String!, input: UpdateUserInput!): User!
+ updateUserByUserName(userName: String!, input: UpdateUserInput!): User!
+ deleteUser(id: String!): User!
}
`
diff --git a/api/src/lib/owner.js b/api/src/lib/owner.js
new file mode 100644
index 0000000..086deeb
--- /dev/null
+++ b/api/src/lib/owner.js
@@ -0,0 +1,43 @@
+import { AuthenticationError, ForbiddenError } from '@redwoodjs/api'
+import { db } from 'src/lib/db'
+
+export const requireOwnership = async ({ userId, userName, partId } = {}) => {
+ // IMPORTANT, don't forget to await this function, as it will only block
+ // unwanted db actions if it has time to look up resources in the db.
+ if (!context.currentUser) {
+ throw new AuthenticationError("You don't have permission to do that.")
+ }
+ if(!userId && !userName && !partId) {
+ throw new ForbiddenError("You don't have access to do that.")
+ }
+
+ if(context.currentUser.roles?.includes('admin')) {
+ return
+ }
+
+ const netlifyUserId = context.currentUser?.sub
+ if(userId && userId !== netlifyUserId) {
+ throw new ForbiddenError("You don't own this resource.")
+ }
+
+ if(userName) {
+ const user = await db.user.findOne({
+ where: { userName },
+ })
+
+ if(!user || user.id !== netlifyUserId) {
+ throw new ForbiddenError("You don't own this resource.")
+ }
+ }
+
+ if(partId) {
+ const user = await db.part.findOne({
+ where: { id: partId },
+ }).user()
+
+ if(!user || user.id !== netlifyUserId) {
+ throw new ForbiddenError("You don't own this resource.")
+ }
+ }
+
+}
diff --git a/api/src/services/comments/comments.js b/api/src/services/comments/comments.js
new file mode 100644
index 0000000..5c46fdf
--- /dev/null
+++ b/api/src/services/comments/comments.js
@@ -0,0 +1,38 @@
+import { db } from 'src/lib/db'
+import { foreignKeyReplacement } from 'src/services/helpers'
+
+export const comments = () => {
+ return db.comment.findMany()
+}
+
+export const comment = ({ id }) => {
+ return db.comment.findOne({
+ where: { id },
+ })
+}
+
+export const createComment = ({ input }) => {
+ return db.comment.create({
+ data: foreignKeyReplacement(input),
+ })
+}
+
+export const updateComment = ({ id, input }) => {
+ return db.comment.update({
+ data: foreignKeyReplacement(input),
+ where: { id },
+ })
+}
+
+export const deleteComment = ({ id }) => {
+ return db.comment.delete({
+ where: { id },
+ })
+}
+
+export const Comment = {
+ user: (_obj, { root }) =>
+ db.comment.findOne({ where: { id: root.id } }).user(),
+ part: (_obj, { root }) =>
+ db.comment.findOne({ where: { id: root.id } }).part(),
+}
diff --git a/api/src/services/contacts/contacts.test.js b/api/src/services/comments/comments.test.js
similarity index 51%
rename from api/src/services/contacts/contacts.test.js
rename to api/src/services/comments/comments.test.js
index fbbbc1e..108fd0f 100644
--- a/api/src/services/contacts/contacts.test.js
+++ b/api/src/services/comments/comments.test.js
@@ -1,8 +1,8 @@
/*
-import { contacts } from './contacts'
+import { comments } from './comments'
*/
-describe('contacts', () => {
+describe('comments', () => {
it('returns true', () => {
expect(true).toBe(true)
})
diff --git a/api/src/services/contacts/contacts.js b/api/src/services/contacts/contacts.js
deleted file mode 100644
index 3481975..0000000
--- a/api/src/services/contacts/contacts.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { UserInputError } from '@redwoodjs/api'
-
-import { db } from 'src/lib/db'
-
-
-const validate = (input) => {
- if (input.email && !input.email.match(/[^@]+@[^.]+\..+/)) {
- throw new UserInputError("Can't create new contact", {
- messages: {
- email: ['is not formatted like an email address'],
- },
- })
- }
-}
-
-export const contacts = () => {
- return db.contact.findMany()
-}
-
-export const createContact = ({ input }) => {
-
- validate(input)
- return db.contact.create({ data: input })
-}
diff --git a/api/src/services/helpers.js b/api/src/services/helpers.js
new file mode 100644
index 0000000..ed474f3
--- /dev/null
+++ b/api/src/services/helpers.js
@@ -0,0 +1,13 @@
+export const foreignKeyReplacement = (input) => {
+ let output = input
+ const foreignKeys = Object.keys(input).filter((k) => k.match(/Id$/))
+ foreignKeys.forEach((key) => {
+ const modelName = key.replace(/Id$/, '')
+ const value = input[key]
+ delete output[key]
+ output = Object.assign(output, {
+ [modelName]: { connect: { id: value } },
+ })
+ })
+ return output
+}
diff --git a/api/src/services/partReactions/partReactions.js b/api/src/services/partReactions/partReactions.js
new file mode 100644
index 0000000..4efd545
--- /dev/null
+++ b/api/src/services/partReactions/partReactions.js
@@ -0,0 +1,58 @@
+import { UserInputError } from '@redwoodjs/api'
+
+import { requireAuth } from 'src/lib/auth'
+import { requireOwnership } from 'src/lib/owner'
+import { db } from 'src/lib/db'
+import { foreignKeyReplacement } from 'src/services/helpers'
+
+export const partReactions = () => {
+ return db.partReaction.findMany()
+}
+
+export const partReaction = ({ id }) => {
+ return db.partReaction.findOne({
+ where: { id },
+ })
+}
+
+export const togglePartReaction = async ({ input }) => {
+ // if write fails emote_userId_partId @@unique constraint, then delete it instead
+ requireAuth()
+ await requireOwnership({userId: input?.userId})
+ const legalReactions = ['❤️', '👍', '😄', '🙌'] // TODO figure out a way of sharing code between FE and BE, so this is consistent with web/src/components/EmojiReaction/EmojiReaction.js
+ if(!legalReactions.includes(input.emote)) {
+ throw new UserInputError(`You can't react with '${input.emote}', only the following are allowed: ${legalReactions.join(', ')}`)
+ }
+ let dbPromise
+ const inputClone = {...input} // TODO foreignKeyReplacement mutates input, which I should fix but am lazy right now
+ try{
+ dbPromise = await db.partReaction.create({
+ data: foreignKeyReplacement(input),
+ })
+ } catch(e) {
+ dbPromise = db.partReaction.delete({
+ where: { emote_userId_partId: inputClone},
+ })
+ }
+ return dbPromise
+}
+
+export const updatePartReaction = ({ id, input }) => {
+ return db.partReaction.update({
+ data: foreignKeyReplacement(input),
+ where: { id },
+ })
+}
+
+export const deletePartReaction = ({ id }) => {
+ return db.partReaction.delete({
+ where: { id },
+ })
+}
+
+export const PartReaction = {
+ user: (_obj, { root }) =>
+ db.partReaction.findOne({ where: { id: root.id } }).user(),
+ part: (_obj, { root }) =>
+ db.partReaction.findOne({ where: { id: root.id } }).part(),
+}
diff --git a/api/src/services/partReactions/partReactions.test.js b/api/src/services/partReactions/partReactions.test.js
new file mode 100644
index 0000000..47d4f20
--- /dev/null
+++ b/api/src/services/partReactions/partReactions.test.js
@@ -0,0 +1,9 @@
+/*
+import { partReactions } from './partReactions'
+*/
+
+describe('partReactions', () => {
+ it('returns true', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/api/src/services/parts/parts.js b/api/src/services/parts/parts.js
index 98c6243..1b96b42 100644
--- a/api/src/services/parts/parts.js
+++ b/api/src/services/parts/parts.js
@@ -1,4 +1,8 @@
import { db } from 'src/lib/db'
+import { foreignKeyReplacement } from 'src/services/helpers'
+import { requireAuth } from 'src/lib/auth'
+import { requireOwnership } from 'src/lib/owner'
+import { user } from 'src/services/users/users'
export const parts = () => {
return db.part.findMany()
@@ -9,22 +13,52 @@ export const part = ({ id }) => {
where: { id },
})
}
-
-export const createPart = ({ input }) => {
- return db.part.create({
- data: input,
+export const partByUserAndTitle = async ({ userName, partTitle }) => {
+ const user = await db.user.findOne({
+ where: {
+ userName
+ }
+ })
+ return db.part.findOne({
+ where: {
+ title_userId: {
+ title: partTitle,
+ userId: user.id,
+ }
+ },
})
}
-export const updatePart = ({ id, input }) => {
+export const createPart = async ({ input }) => {
+ requireAuth()
+ return db.part.create({
+ data: foreignKeyReplacement(input),
+ })
+}
+
+export const updatePart = async ({ id, input }) => {
+ requireAuth()
+ await requireOwnership({partId: id})
+ if(input.title) {
+ input.title = input.title.replace(/([^a-zA-Z\d_:])/g, '-')
+ }
return db.part.update({
- data: input,
+ data: foreignKeyReplacement(input),
where: { id },
})
}
export const deletePart = ({ id }) => {
+ requireAuth()
return db.part.delete({
where: { id },
})
}
+
+export const Part = {
+ user: (_obj, { root }) => db.part.findOne({ where: { id: root.id } }).user(),
+ Comment: (_obj, { root }) =>
+ db.part.findOne({ where: { id: root.id } }).Comment(),
+ Reaction: (_obj, { root }) =>
+ db.part.findOne({ where: { id: root.id } }).Reaction({where: {userId: _obj.userId}}),
+}
diff --git a/api/src/services/posts/posts.js b/api/src/services/posts/posts.js
deleted file mode 100644
index 8912a71..0000000
--- a/api/src/services/posts/posts.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { db } from 'src/lib/db'
-import { requireAuth } from 'src/lib/auth'
-
-export const posts = () => {
- return db.post.findMany()
-}
-
-export const post = ({ id }) => {
- return db.post.findOne({
- where: { id },
- })
-}
-
-export const createPost = ({ input }) => {
- requireAuth()
- return db.post.create({
- data: input,
- })
-}
-
-export const updatePost = ({ id, input }) => {
- requireAuth()
- return db.post.update({
- data: input,
- where: { id },
- })
-}
-
-export const deletePost = ({ id }) => {
- requireAuth()
- return db.post.delete({
- where: { id },
- })
-}
diff --git a/api/src/services/posts/posts.test.js b/api/src/services/posts/posts.test.js
deleted file mode 100644
index f23483a..0000000
--- a/api/src/services/posts/posts.test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
-import { posts } from './posts'
-*/
-
-describe('posts', () => {
- it('returns true', () => {
- expect(true).toBe(true)
- })
-})
diff --git a/api/src/services/users/users.js b/api/src/services/users/users.js
index 3d3675c..cae1557 100644
--- a/api/src/services/users/users.js
+++ b/api/src/services/users/users.js
@@ -1,5 +1,7 @@
import { db } from 'src/lib/db'
import { requireAuth } from 'src/lib/auth'
+import { requireOwnership } from 'src/lib/owner'
+import { UserInputError } from '@redwoodjs/api'
export const users = () => {
requireAuth({ role: 'admin' })
@@ -7,17 +9,21 @@ export const users = () => {
}
export const user = ({ id }) => {
- requireAuth()
return db.user.findOne({
where: { id },
})
}
-export const createUser = ({ input }) => {
- requireAuth({ role: 'admin' })
- return createUserInsecure({input})
+export const userName = ({ userName }) => {
+ return db.user.findOne({
+ where: { userName },
+ })
}
+export const createUser = ({ input }) => {
+ requireAuth({ role: 'admin' })
+ createUserInsecure({input})
+}
export const createUserInsecure = ({ input }) => {
return db.user.create({
data: input,
@@ -32,9 +38,36 @@ export const updateUser = ({ id, input }) => {
})
}
+export const updateUserByUserName = async ({ userName, input }) => {
+ requireAuth()
+ await requireOwnership({userName})
+ if(input.userName) {
+ input.userName = input.userName.replace(/([^a-zA-Z\d_:])/g, '-')
+ }
+ if(input.userName && ['new', 'edit', 'update'].includes(input.userName)) { //TODO complete this and use a regexp so that it's not case sensitive, don't want someone with the userName eDiT
+ throw new UserInputError(`You've tried to used a protected word as you userName, try something other than `)
+ }
+ return db.user.update({
+ data: input,
+ where: { userName },
+ })
+}
+
export const deleteUser = ({ id }) => {
requireAuth({ role: 'admin' })
return db.user.delete({
where: { id },
})
}
+
+export const User = {
+ Parts: (_obj, { root }) => db.user.findOne({ where: { id: root.id } }).Part(),
+ Part: (_obj, { root, ...rest }) => _obj.partTitle && db.part.findOne({where: { title_userId: {
+ title: _obj.partTitle,
+ userId: root.id,
+ }}}),
+ Reaction: (_obj, { root }) =>
+ db.user.findOne({ where: { id: root.id } }).Reaction(),
+ Comment: (_obj, { root }) =>
+ db.user.findOne({ where: { id: root.id } }).Comment(),
+}
diff --git a/web/package.json b/web/package.json
index a9942bc..e9ac1d7 100644
--- a/web/package.json
+++ b/web/package.json
@@ -20,6 +20,7 @@
"@redwoodjs/web": "^0.19.2",
"cloudinary-react": "^1.6.7",
"controlkit": "^0.1.9",
+ "get-active-classes": "^0.0.11",
"golden-layout": "^1.5.9",
"jquery": "^3.5.1",
"monaco-editor": "^0.20.0",
diff --git a/web/src/Routes.js b/web/src/Routes.js
index 8255681..547071b 100644
--- a/web/src/Routes.js
+++ b/web/src/Routes.js
@@ -12,31 +12,39 @@ import { Router, Route, Private } from '@redwoodjs/router'
const Routes = () => {
return (
- {post.title}
-
-
| Id | -{post.id} | +{comment.id} | |
|---|---|---|---|
| Title | -{post.title} | +Text | +{comment.text} |
| Body | -{post.body} | +User id | +{comment.userId} | +
| Part id | +{comment.partId} | ||
| Created at | -{timeTag(post.createdAt)} | +{timeTag(comment.createdAt)} | +|
| Updated at | +{timeTag(comment.updatedAt)} |