Compare commits
1 Commits
main
...
express-mo
Author | SHA1 | Date | |
---|---|---|---|
69b54f4e85 |
@ -1 +0,0 @@
|
|||||||
node_modules/
|
|
@ -1,3 +0,0 @@
|
|||||||
SENDGRID_API_KEY=
|
|
||||||
JWT_SECRET=
|
|
||||||
SITE_URL=test.com
|
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,12 +1,8 @@
|
|||||||
/node_modules
|
/node_modules
|
||||||
|
|
||||||
/dist
|
/build
|
||||||
|
|
||||||
.env
|
.env.local
|
||||||
|
|
||||||
*.gen.ts
|
|
||||||
|
|
||||||
*.local*
|
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
|
17
Dockerfile
17
Dockerfile
@ -1,17 +0,0 @@
|
|||||||
FROM node:alpine AS builder
|
|
||||||
WORKDIR /backend
|
|
||||||
COPY package.json /backend/package.json
|
|
||||||
RUN yarn
|
|
||||||
COPY . /backend
|
|
||||||
RUN yarn prisma generate && yarn codegen && yarn build
|
|
||||||
|
|
||||||
FROM node:alpine
|
|
||||||
WORKDIR /backend
|
|
||||||
COPY --from=builder /backend/dist /backend
|
|
||||||
COPY package.json /backend/package.json
|
|
||||||
RUN yarn install --prod
|
|
||||||
COPY --from=builder /backend/node_modules/@prisma/client /backend/node_modules/@prisma/client
|
|
||||||
COPY --from=builder /backend/node_modules/.prisma/client/ /backend/node_modules/.prisma/client/
|
|
||||||
COPY --from=builder /backend/prisma /backend/prisma
|
|
||||||
USER node
|
|
||||||
CMD [ "node", "./index.js" ]
|
|
21
LICENCE
21
LICENCE
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 Ditriy Shishkov <me@dmitriy.com> (https://dmitriy.icu)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
27
README.md
27
README.md
@ -1,27 +0,0 @@
|
|||||||
# QuestionForm Backend
|
|
||||||
|
|
||||||
Backend for QuestionForm application.
|
|
||||||
|
|
||||||
# Built with:
|
|
||||||
|
|
||||||
- Prisma
|
|
||||||
- Graphql
|
|
||||||
- Apollo Server
|
|
||||||
- Graphql code generator
|
|
||||||
- SendGrid
|
|
||||||
|
|
||||||
# Setting up development environment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ git clone https://github.com/Dm1tr1y147/questionForm_backend
|
|
||||||
$ yarn
|
|
||||||
$ mv .env.example .env && vim .env
|
|
||||||
$ mv prisma/.env.example prisma/.env && vim .env
|
|
||||||
$ prisma migrate save --experimental && prisma migrate up --experimental
|
|
||||||
$ prisma generate
|
|
||||||
$ yarn dev
|
|
||||||
```
|
|
||||||
|
|
||||||
# API
|
|
||||||
|
|
||||||
_...coming soon..._
|
|
12
codegen.yml
12
codegen.yml
@ -1,12 +0,0 @@
|
|||||||
overwrite: true
|
|
||||||
schema: 'src/typeDefs/typeDefs.gql'
|
|
||||||
documents: null
|
|
||||||
generates:
|
|
||||||
src/typeDefs/typeDefs.gen.ts:
|
|
||||||
config:
|
|
||||||
useIndexSignature: true
|
|
||||||
wrapFieldDefinitions: true
|
|
||||||
enumsAsTypes: true
|
|
||||||
plugins:
|
|
||||||
- 'typescript'
|
|
||||||
- 'typescript-resolvers'
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"],
|
|
||||||
"watch": ["src"],
|
|
||||||
"exec": "yarn start",
|
|
||||||
"ext": "ts"
|
|
||||||
}
|
|
41
package.json
41
package.json
@ -1,38 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "backend",
|
"name": "backend",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "src/index.ts",
|
"main": "index.js",
|
||||||
"private": "true",
|
"repository": "https://github.com/Dm1tr1y147/questionForm_backend.git",
|
||||||
|
"author": "Dm1tr1y147 <me@dmitriy.icu>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"devDependencies": {
|
||||||
"@prisma/client": "^2.7.1",
|
"@types/express": "^4.17.8",
|
||||||
"@sendgrid/mail": "^7.2.6",
|
"@types/mongoose": "^5.7.36",
|
||||||
"apollo-server-express": "^2.18.2",
|
"@types/node": "^14.11.2",
|
||||||
"express-jwt": "^6.0.0",
|
"ts-node-dev": "^1.0.0-pre.63",
|
||||||
"graphql": "^15.3.0",
|
"typescript": "^4.0.3"
|
||||||
"jsonwebtoken": "^8.5.1",
|
|
||||||
"jwks-rsa": "^1.10.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon",
|
"start": "ts-node-dev src/main.ts"
|
||||||
"start": "ts-node src/index.ts",
|
|
||||||
"copy-assets": "cp src/typeDefs/typeDefs.gql dist/typeDefs/typeDefs.gql",
|
|
||||||
"build": "tsc && yarn copy-assets",
|
|
||||||
"codegen": "graphql-codegen --config codegen.yml",
|
|
||||||
"lint": "eslint",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"dependencies": {
|
||||||
"@graphql-codegen/cli": "1.17.10",
|
"mongoose": "^5.10.7"
|
||||||
"@graphql-codegen/introspection": "1.18.0",
|
|
||||||
"@graphql-codegen/typescript": "1.17.10",
|
|
||||||
"@graphql-codegen/typescript-resolvers": "1.17.10",
|
|
||||||
"@prisma/cli": "2.8.1",
|
|
||||||
"@types/dotenv": "^8.2.0",
|
|
||||||
"@types/jsonwebtoken": "^8.5.0",
|
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"nodemon": "^2.0.4",
|
|
||||||
"ts-node": "^9.0.0",
|
|
||||||
"typescript": "^4.0.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
DATABASE_URL="postgres://"
|
|
@ -1,219 +0,0 @@
|
|||||||
# Migration `20201006125838-initial-migration`
|
|
||||||
|
|
||||||
This migration has been generated by Dm1tr1y147 at 10/6/2020, 5:58:38 PM.
|
|
||||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
|
||||||
|
|
||||||
## Database Steps
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TYPE "public"."ChoiseType" AS ENUM ('SELECT', 'CHECK', 'CHOOSE')
|
|
||||||
|
|
||||||
CREATE TYPE "public"."AnswerType" AS ENUM ('INPUT', 'CHOISE')
|
|
||||||
|
|
||||||
CREATE TABLE "public"."Form" (
|
|
||||||
"title" text NOT NULL ,
|
|
||||||
"dateCreated" timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"userId" integer NOT NULL ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."ChoisesQuestion" (
|
|
||||||
"title" text NOT NULL ,
|
|
||||||
"type" "ChoiseType" NOT NULL ,
|
|
||||||
"number" integer NOT NULL ,
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"formId" integer ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."Variant" (
|
|
||||||
"text" text NOT NULL ,
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"choisesQuestionId" integer ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."InputQuestion" (
|
|
||||||
"title" text NOT NULL ,
|
|
||||||
"number" integer NOT NULL ,
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"formId" integer ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."FormSubmission" (
|
|
||||||
"date" timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"formId" integer ,
|
|
||||||
"userId" integer NOT NULL ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."Answer" (
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"userInput" text NOT NULL ,
|
|
||||||
"userChoise" integer NOT NULL ,
|
|
||||||
"type" "AnswerType" NOT NULL ,
|
|
||||||
"formSubmissionId" integer ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
CREATE TABLE "public"."User" (
|
|
||||||
"id" integer NOT NULL ,
|
|
||||||
"name" text NOT NULL ,
|
|
||||||
PRIMARY KEY ("id")
|
|
||||||
)
|
|
||||||
|
|
||||||
ALTER TABLE "public"."Form" ADD FOREIGN KEY ("userId")REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."ChoisesQuestion" ADD FOREIGN KEY ("formId")REFERENCES "public"."Form"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."Variant" ADD FOREIGN KEY ("choisesQuestionId")REFERENCES "public"."ChoisesQuestion"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."InputQuestion" ADD FOREIGN KEY ("formId")REFERENCES "public"."Form"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."FormSubmission" ADD FOREIGN KEY ("userId")REFERENCES "public"."User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."FormSubmission" ADD FOREIGN KEY ("formId")REFERENCES "public"."Form"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
|
||||||
|
|
||||||
ALTER TABLE "public"."Answer" ADD FOREIGN KEY ("formSubmissionId")REFERENCES "public"."FormSubmission"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
```diff
|
|
||||||
diff --git schema.prisma schema.prisma
|
|
||||||
migration ..20201006125838-initial-migration
|
|
||||||
--- datamodel.dml
|
|
||||||
+++ datamodel.dml
|
|
||||||
@@ -1,0 +1,126 @@
|
|
||||||
+// This is your Prisma schema file,
|
|
||||||
+// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
+
|
|
||||||
+datasource db {
|
|
||||||
+ provider = "postgres"
|
|
||||||
+ url = "***"
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+generator client {
|
|
||||||
+ provider = "prisma-client-js"
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+// model User {
|
|
||||||
+// id Int @id @default(autoincrement())
|
|
||||||
+// name String
|
|
||||||
+// email String?
|
|
||||||
+// createdAt DateTime @default(now())
|
|
||||||
+// polls Poll[]
|
|
||||||
+// }
|
|
||||||
+
|
|
||||||
+// model Poll {
|
|
||||||
+// id Int @id @default(autoincrement())
|
|
||||||
+// User User? @relation(fields: [userId], references: [id])
|
|
||||||
+// userId Int?
|
|
||||||
+// title String
|
|
||||||
+// description String?
|
|
||||||
+// slug String @unique @default(cuid())
|
|
||||||
+// questions Question[]
|
|
||||||
+// createdAt DateTime @default(now())
|
|
||||||
+// }
|
|
||||||
+
|
|
||||||
+// model Question {
|
|
||||||
+// id Int @id @default(autoincrement())
|
|
||||||
+// Poll Poll? @relation(fields: [pollId], references: [id])
|
|
||||||
+// pollId Int?
|
|
||||||
+// title String
|
|
||||||
+// variants Variant[]
|
|
||||||
+// }
|
|
||||||
+
|
|
||||||
+// model Variant {
|
|
||||||
+// id Int @id @default(autoincrement())
|
|
||||||
+// Question Question? @relation(fields: [questionId], references: [id])
|
|
||||||
+// questionId Int?
|
|
||||||
+// text String
|
|
||||||
+// count Int @default(0)
|
|
||||||
+// }
|
|
||||||
+
|
|
||||||
+model Form {
|
|
||||||
+ title String
|
|
||||||
+ choisesQuestions ChoisesQuestion[]
|
|
||||||
+ inputQuestions InputQuestion[]
|
|
||||||
+ submissions FormSubmission[]
|
|
||||||
+ dateCreated DateTime @default(now())
|
|
||||||
+
|
|
||||||
+ id Int @id
|
|
||||||
+ userId Int
|
|
||||||
+ author User @relation(fields: [userId], references: [id])
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model ChoisesQuestion {
|
|
||||||
+ title String
|
|
||||||
+ variants Variant[]
|
|
||||||
+ type ChoiseType
|
|
||||||
+ number Int
|
|
||||||
+
|
|
||||||
+ id Int @id
|
|
||||||
+ Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
+ formId Int?
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model Variant {
|
|
||||||
+ text String
|
|
||||||
+
|
|
||||||
+ id Int @id
|
|
||||||
+ ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
+ choisesQuestionId Int?
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model InputQuestion {
|
|
||||||
+ title String
|
|
||||||
+ number Int
|
|
||||||
+
|
|
||||||
+ id Int @id
|
|
||||||
+ Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
+ formId Int?
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model FormSubmission {
|
|
||||||
+ answers Answer[]
|
|
||||||
+ date DateTime @default(now())
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ id Int @id
|
|
||||||
+ user User @relation(fields: [userId], references: [id])
|
|
||||||
+ Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
+ formId Int?
|
|
||||||
+ userId Int
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model Answer {
|
|
||||||
+ id Int @id
|
|
||||||
+ userInput String
|
|
||||||
+ userChoise Int
|
|
||||||
+ type AnswerType
|
|
||||||
+ FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
+ formSubmissionId Int?
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+enum ChoiseType {
|
|
||||||
+ SELECT
|
|
||||||
+ CHECK
|
|
||||||
+ CHOOSE
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+enum AnswerType {
|
|
||||||
+ INPUT
|
|
||||||
+ CHOISE
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model User {
|
|
||||||
+ id Int @id
|
|
||||||
+ name String
|
|
||||||
+
|
|
||||||
+ forms Form[]
|
|
||||||
+ formsSubmissions FormSubmission[]
|
|
||||||
+}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = "***"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
// model User {
|
|
||||||
// id Int @id @default(autoincrement())
|
|
||||||
// name String
|
|
||||||
// email String?
|
|
||||||
// createdAt DateTime @default(now())
|
|
||||||
// polls Poll[]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// model Poll {
|
|
||||||
// id Int @id @default(autoincrement())
|
|
||||||
// User User? @relation(fields: [userId], references: [id])
|
|
||||||
// userId Int?
|
|
||||||
// title String
|
|
||||||
// description String?
|
|
||||||
// slug String @unique @default(cuid())
|
|
||||||
// questions Question[]
|
|
||||||
// createdAt DateTime @default(now())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// model Question {
|
|
||||||
// id Int @id @default(autoincrement())
|
|
||||||
// Poll Poll? @relation(fields: [pollId], references: [id])
|
|
||||||
// pollId Int?
|
|
||||||
// title String
|
|
||||||
// variants Variant[]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// model Variant {
|
|
||||||
// id Int @id @default(autoincrement())
|
|
||||||
// Question Question? @relation(fields: [questionId], references: [id])
|
|
||||||
// questionId Int?
|
|
||||||
// text String
|
|
||||||
// count Int @default(0)
|
|
||||||
// }
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
|
|
||||||
id Int @id
|
|
||||||
userId Int
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
|
|
||||||
|
|
||||||
id Int @id
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
id Int @id
|
|
||||||
userInput String
|
|
||||||
userChoise Int
|
|
||||||
type AnswerType
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
id Int @id
|
|
||||||
name String
|
|
||||||
|
|
||||||
forms Form[]
|
|
||||||
formsSubmissions FormSubmission[]
|
|
||||||
}
|
|
@ -1,759 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.3.14-fixed",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"tag": "CreateEnum",
|
|
||||||
"enum": "ChoiseType",
|
|
||||||
"values": [
|
|
||||||
"SELECT",
|
|
||||||
"CHECK",
|
|
||||||
"CHOOSE"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateEnum",
|
|
||||||
"enum": "AnswerType",
|
|
||||||
"values": [
|
|
||||||
"INPUT",
|
|
||||||
"CHOISE"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateSource",
|
|
||||||
"source": "db"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Source",
|
|
||||||
"source": "db"
|
|
||||||
},
|
|
||||||
"argument": "provider",
|
|
||||||
"value": "\"postgres\""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Source",
|
|
||||||
"source": "db"
|
|
||||||
},
|
|
||||||
"argument": "url",
|
|
||||||
"value": "\"***\""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "Form"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "title",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "choisesQuestions",
|
|
||||||
"type": "ChoisesQuestion",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "inputQuestions",
|
|
||||||
"type": "InputQuestion",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "submissions",
|
|
||||||
"type": "FormSubmission",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "dateCreated",
|
|
||||||
"type": "DateTime",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "dateCreated"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "dateCreated"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "now()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "userId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "author",
|
|
||||||
"type": "User",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "author"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "author"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[userId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "author"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "ChoisesQuestion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "title",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "variants",
|
|
||||||
"type": "Variant",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "type",
|
|
||||||
"type": "ChoiseType",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "number",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "Form",
|
|
||||||
"type": "Form",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[formId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "formId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "Variant"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "text",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "ChoisesQuestion",
|
|
||||||
"type": "ChoisesQuestion",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "ChoisesQuestion"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "ChoisesQuestion"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[choisesQuestionId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "ChoisesQuestion"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "choisesQuestionId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "InputQuestion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "title",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "number",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "Form",
|
|
||||||
"type": "Form",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[formId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "formId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "FormSubmission"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "answers",
|
|
||||||
"type": "Answer",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "date",
|
|
||||||
"type": "DateTime",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "date"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "date"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "now()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "user",
|
|
||||||
"type": "User",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "user"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "user"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[userId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "user"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "Form",
|
|
||||||
"type": "Form",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[formId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "Form"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "formId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "userId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateModel",
|
|
||||||
"model": "Answer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "id",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "id"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "userInput",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "userChoise",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "type",
|
|
||||||
"type": "AnswerType",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "FormSubmission",
|
|
||||||
"type": "FormSubmission",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "FormSubmission"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "FormSubmission"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "fields",
|
|
||||||
"value": "[formSubmissionId]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "FormSubmission"
|
|
||||||
},
|
|
||||||
"directive": "relation"
|
|
||||||
},
|
|
||||||
"argument": "references",
|
|
||||||
"value": "[id]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "formSubmissionId",
|
|
||||||
"type": "Int",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": "CreateField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "name",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "forms",
|
|
||||||
"type": "Form",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "formsSubmissions",
|
|
||||||
"type": "FormSubmission",
|
|
||||||
"arity": "List"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
# Migration `20201006185953-improved-schema-structure`
|
|
||||||
|
|
||||||
This migration has been generated by Dm1tr1y147 at 10/6/2020, 11:59:53 PM.
|
|
||||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
|
||||||
|
|
||||||
## Database Steps
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE SEQUENCE "answer_id_seq";
|
|
||||||
ALTER TABLE "public"."Answer" ALTER COLUMN "id" SET DEFAULT nextval('answer_id_seq');
|
|
||||||
ALTER SEQUENCE "answer_id_seq" OWNED BY "public"."Answer"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "choisesquestion_id_seq";
|
|
||||||
ALTER TABLE "public"."ChoisesQuestion" ALTER COLUMN "id" SET DEFAULT nextval('choisesquestion_id_seq');
|
|
||||||
ALTER SEQUENCE "choisesquestion_id_seq" OWNED BY "public"."ChoisesQuestion"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "form_id_seq";
|
|
||||||
ALTER TABLE "public"."Form" ALTER COLUMN "id" SET DEFAULT nextval('form_id_seq');
|
|
||||||
ALTER SEQUENCE "form_id_seq" OWNED BY "public"."Form"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "formsubmission_id_seq";
|
|
||||||
ALTER TABLE "public"."FormSubmission" ALTER COLUMN "id" SET DEFAULT nextval('formsubmission_id_seq');
|
|
||||||
ALTER SEQUENCE "formsubmission_id_seq" OWNED BY "public"."FormSubmission"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "inputquestion_id_seq";
|
|
||||||
ALTER TABLE "public"."InputQuestion" ALTER COLUMN "id" SET DEFAULT nextval('inputquestion_id_seq');
|
|
||||||
ALTER SEQUENCE "inputquestion_id_seq" OWNED BY "public"."InputQuestion"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "user_id_seq";
|
|
||||||
ALTER TABLE "public"."User" ALTER COLUMN "id" SET DEFAULT nextval('user_id_seq');
|
|
||||||
ALTER SEQUENCE "user_id_seq" OWNED BY "public"."User"."id"
|
|
||||||
|
|
||||||
CREATE SEQUENCE "variant_id_seq";
|
|
||||||
ALTER TABLE "public"."Variant" ALTER COLUMN "id" SET DEFAULT nextval('variant_id_seq');
|
|
||||||
ALTER SEQUENCE "variant_id_seq" OWNED BY "public"."Variant"."id"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
```diff
|
|
||||||
diff --git schema.prisma schema.prisma
|
|
||||||
migration 20201006125838-initial-migration..20201006185953-improved-schema-structure
|
|
||||||
--- datamodel.dml
|
|
||||||
+++ datamodel.dml
|
|
||||||
@@ -2,125 +2,90 @@
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
- url = "***"
|
|
||||||
+ url = "***"
|
|
||||||
}
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
-// model User {
|
|
||||||
-// id Int @id @default(autoincrement())
|
|
||||||
-// name String
|
|
||||||
-// email String?
|
|
||||||
-// createdAt DateTime @default(now())
|
|
||||||
-// polls Poll[]
|
|
||||||
-// }
|
|
||||||
-
|
|
||||||
-// model Poll {
|
|
||||||
-// id Int @id @default(autoincrement())
|
|
||||||
-// User User? @relation(fields: [userId], references: [id])
|
|
||||||
-// userId Int?
|
|
||||||
-// title String
|
|
||||||
-// description String?
|
|
||||||
-// slug String @unique @default(cuid())
|
|
||||||
-// questions Question[]
|
|
||||||
-// createdAt DateTime @default(now())
|
|
||||||
-// }
|
|
||||||
-
|
|
||||||
-// model Question {
|
|
||||||
-// id Int @id @default(autoincrement())
|
|
||||||
-// Poll Poll? @relation(fields: [pollId], references: [id])
|
|
||||||
-// pollId Int?
|
|
||||||
-// title String
|
|
||||||
-// variants Variant[]
|
|
||||||
-// }
|
|
||||||
-
|
|
||||||
-// model Variant {
|
|
||||||
-// id Int @id @default(autoincrement())
|
|
||||||
-// Question Question? @relation(fields: [questionId], references: [id])
|
|
||||||
-// questionId Int?
|
|
||||||
-// text String
|
|
||||||
-// count Int @default(0)
|
|
||||||
-// }
|
|
||||||
-
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
+ author User @relation(fields: [userId], references: [id])
|
|
||||||
- id Int @id
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
- author User @relation(fields: [userId], references: [id])
|
|
||||||
}
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
- id Int @id
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
- id Int @id
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
- id Int @id
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
+enum ChoiseType {
|
|
||||||
+ SELECT
|
|
||||||
+ CHECK
|
|
||||||
+ CHOOSE
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+model User {
|
|
||||||
+ name String
|
|
||||||
+ forms Form[]
|
|
||||||
+
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
+ formsSubmissions FormSubmission[]
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
+ user User @relation(fields: [userId], references: [id])
|
|
||||||
-
|
|
||||||
- id Int @id
|
|
||||||
- user User @relation(fields: [userId], references: [id])
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
+ userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
- userId Int
|
|
||||||
}
|
|
||||||
model Answer {
|
|
||||||
- id Int @id
|
|
||||||
- userInput String
|
|
||||||
- userChoise Int
|
|
||||||
- type AnswerType
|
|
||||||
+ userInput String
|
|
||||||
+ userChoise Int
|
|
||||||
+ type AnswerType
|
|
||||||
+
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
-enum ChoiseType {
|
|
||||||
- SELECT
|
|
||||||
- CHECK
|
|
||||||
- CHOOSE
|
|
||||||
-}
|
|
||||||
-
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
||||||
-
|
|
||||||
-model User {
|
|
||||||
- id Int @id
|
|
||||||
- name String
|
|
||||||
-
|
|
||||||
- forms Form[]
|
|
||||||
- formsSubmissions FormSubmission[]
|
|
||||||
-}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = "***"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
forms Form[]
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formsSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
userInput String
|
|
||||||
userChoise Int
|
|
||||||
type AnswerType
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.3.14-fixed",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Form",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "ChoisesQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Variant",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "InputQuestion",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "FormSubmission",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "id"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "autoincrement()"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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()"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
# Migration `20201007134933-fix-optional-values`
|
|
||||||
|
|
||||||
This migration has been generated by Dm1tr1y147 at 10/7/2020, 6:49:33 PM.
|
|
||||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
|
||||||
|
|
||||||
## Database Steps
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER TABLE "public"."Answer" ALTER COLUMN "userInput" DROP NOT NULL,
|
|
||||||
ALTER COLUMN "userChoise" DROP NOT NULL
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
```diff
|
|
||||||
diff --git schema.prisma schema.prisma
|
|
||||||
migration 20201006185953-improved-schema-structure..20201007134933-fix-optional-values
|
|
||||||
--- datamodel.dml
|
|
||||||
+++ datamodel.dml
|
|
||||||
@@ -2,9 +2,9 @@
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
- url = "***"
|
|
||||||
+ url = "***"
|
|
||||||
}
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
@@ -75,10 +75,10 @@
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
model Answer {
|
|
||||||
- userInput String
|
|
||||||
- userChoise Int
|
|
||||||
+ userInput String?
|
|
||||||
+ userChoise Int?
|
|
||||||
type AnswerType
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = "***"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
forms Form[]
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formsSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
userInput String?
|
|
||||||
userChoise Int?
|
|
||||||
type AnswerType
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.3.14-fixed",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"tag": "UpdateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "userInput",
|
|
||||||
"arity": "Optional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "UpdateField",
|
|
||||||
"model": "Answer",
|
|
||||||
"field": "userChoise",
|
|
||||||
"arity": "Optional"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
# Migration `20201009145620-add-user-email`
|
|
||||||
|
|
||||||
This migration has been generated by Dm1tr1y147 at 10/9/2020, 7:56:20 PM.
|
|
||||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
|
||||||
|
|
||||||
## Database Steps
|
|
||||||
|
|
||||||
```sql
|
|
||||||
ALTER TABLE "public"."User" ADD COLUMN "email" text NOT NULL DEFAULT E'test@mail.com'
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX "User.email_unique" ON "public"."User"("email")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
```diff
|
|
||||||
diff --git schema.prisma schema.prisma
|
|
||||||
migration 20201007134933-fix-optional-values..20201009145620-add-user-email
|
|
||||||
--- datamodel.dml
|
|
||||||
+++ datamodel.dml
|
|
||||||
@@ -2,9 +2,9 @@
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
- url = "***"
|
|
||||||
+ url = "***"
|
|
||||||
}
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
@@ -57,8 +57,9 @@
|
|
||||||
}
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
+ email String @unique @default("test@mail.com")
|
|
||||||
forms Form[]
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formsSubmissions FormSubmission[]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = "***"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
email String @unique @default("test@mail.com")
|
|
||||||
forms Form[]
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formsSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
userInput String?
|
|
||||||
userChoise Int?
|
|
||||||
type AnswerType
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.3.14-fixed",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "email",
|
|
||||||
"type": "String",
|
|
||||||
"arity": "Required"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "User",
|
|
||||||
"field": "email"
|
|
||||||
},
|
|
||||||
"directive": "unique"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateDirective",
|
|
||||||
"location": {
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "User",
|
|
||||||
"field": "email"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "CreateArgument",
|
|
||||||
"location": {
|
|
||||||
"tag": "Directive",
|
|
||||||
"path": {
|
|
||||||
"tag": "Field",
|
|
||||||
"model": "User",
|
|
||||||
"field": "email"
|
|
||||||
},
|
|
||||||
"directive": "default"
|
|
||||||
},
|
|
||||||
"argument": "",
|
|
||||||
"value": "\"test@mail.com\""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
# Migration `20201104091229-renamed-user-form-submissions-name`
|
|
||||||
|
|
||||||
This migration has been generated by Dm1tr1y147 at 11/4/2020, 2:12:29 PM.
|
|
||||||
You can check out the [state of the schema](./schema.prisma) after the migration.
|
|
||||||
|
|
||||||
## Database Steps
|
|
||||||
|
|
||||||
```sql
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changes
|
|
||||||
|
|
||||||
```diff
|
|
||||||
diff --git schema.prisma schema.prisma
|
|
||||||
migration 20201009145620-add-user-email..20201104091229-renamed-user-form-submissions-name
|
|
||||||
--- datamodel.dml
|
|
||||||
+++ datamodel.dml
|
|
||||||
@@ -2,9 +2,9 @@
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
- url = "***"
|
|
||||||
+ url = "***"
|
|
||||||
}
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
@@ -60,10 +60,10 @@
|
|
||||||
name String
|
|
||||||
email String @unique @default("test@mail.com")
|
|
||||||
forms Form[]
|
|
||||||
- id Int @id @default(autoincrement())
|
|
||||||
- formsSubmissions FormSubmission[]
|
|
||||||
+ id Int @id @default(autoincrement())
|
|
||||||
+ formSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = "***"
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
email String @unique @default("test@mail.com")
|
|
||||||
forms Form[]
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
userInput String?
|
|
||||||
userChoise Int?
|
|
||||||
type AnswerType
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.3.14-fixed",
|
|
||||||
"steps": [
|
|
||||||
{
|
|
||||||
"tag": "CreateField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "formSubmissions",
|
|
||||||
"type": "FormSubmission",
|
|
||||||
"arity": "List"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tag": "DeleteField",
|
|
||||||
"model": "User",
|
|
||||||
"field": "formsSubmissions"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
# Prisma Migrate lockfile v1
|
|
||||||
|
|
||||||
20201006125838-initial-migration
|
|
||||||
20201006185953-improved-schema-structure
|
|
||||||
20201007134933-fix-optional-values
|
|
||||||
20201009145620-add-user-email
|
|
||||||
20201104091229-renamed-user-form-submissions-name
|
|
@ -1,92 +0,0 @@
|
|||||||
// This is your Prisma schema file,
|
|
||||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
||||||
|
|
||||||
datasource db {
|
|
||||||
provider = "postgres"
|
|
||||||
url = env("DATABASE_URL")
|
|
||||||
}
|
|
||||||
|
|
||||||
generator client {
|
|
||||||
provider = "prisma-client-js"
|
|
||||||
}
|
|
||||||
|
|
||||||
model Form {
|
|
||||||
title String
|
|
||||||
choisesQuestions ChoisesQuestion[]
|
|
||||||
inputQuestions InputQuestion[]
|
|
||||||
submissions FormSubmission[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
author User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
}
|
|
||||||
|
|
||||||
model ChoisesQuestion {
|
|
||||||
title String
|
|
||||||
variants Variant[]
|
|
||||||
type ChoiseType
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Variant {
|
|
||||||
text String
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
ChoisesQuestion ChoisesQuestion? @relation(fields: [choisesQuestionId], references: [id])
|
|
||||||
choisesQuestionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model InputQuestion {
|
|
||||||
title String
|
|
||||||
number Int
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
SELECT
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
}
|
|
||||||
|
|
||||||
model User {
|
|
||||||
name String
|
|
||||||
email String @unique @default("test@mail.com")
|
|
||||||
forms Form[]
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
formSubmissions FormSubmission[]
|
|
||||||
}
|
|
||||||
|
|
||||||
model FormSubmission {
|
|
||||||
answers Answer[]
|
|
||||||
date DateTime @default(now())
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
userId Int
|
|
||||||
Form Form? @relation(fields: [formId], references: [id])
|
|
||||||
formId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Answer {
|
|
||||||
userInput String?
|
|
||||||
userChoise Int?
|
|
||||||
type AnswerType
|
|
||||||
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
FormSubmission FormSubmission? @relation(fields: [formSubmissionId], references: [id])
|
|
||||||
formSubmissionId Int?
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
INPUT
|
|
||||||
CHOISE
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
import jwt from 'jsonwebtoken'
|
|
||||||
import {
|
|
||||||
ApolloError,
|
|
||||||
AuthenticationError,
|
|
||||||
ForbiddenError,
|
|
||||||
} from 'apollo-server-express'
|
|
||||||
import { PrismaClient } from '@prisma/client'
|
|
||||||
|
|
||||||
import { CheckRightsAndResolve } from './types'
|
|
||||||
import { getDBFormAuthor } from '../db'
|
|
||||||
import { sendToken } from './mailer'
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') require('dotenv').config()
|
|
||||||
|
|
||||||
const checkRightsAndResolve: CheckRightsAndResolve = async (params) => {
|
|
||||||
const { user, expected, controller } = params
|
|
||||||
|
|
||||||
if (!user) throw new AuthenticationError('Authorization required')
|
|
||||||
|
|
||||||
if (expected.id && expected.self) return controller(expected.id || user.id)
|
|
||||||
if (expected.self) return controller(user.id)
|
|
||||||
if (!expected.id || user.id == expected.id) return controller()
|
|
||||||
|
|
||||||
throw new ForbiddenError('Access denied')
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFormAuthor = async (db: PrismaClient, id: number) => {
|
|
||||||
const author = await getDBFormAuthor(db, id)
|
|
||||||
|
|
||||||
if (!author) throw new ApolloError('Not found', 'NOTFOUND')
|
|
||||||
|
|
||||||
const authorId = author.author.id
|
|
||||||
|
|
||||||
return authorId
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokenGenerate = (email: string, id: number) => {
|
|
||||||
const token = jwt.sign({ email, id }, '' + process.env.JWT_SECRET, {
|
|
||||||
algorithm: 'HS256',
|
|
||||||
expiresIn: '7 days',
|
|
||||||
})
|
|
||||||
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
|
|
||||||
const genAndSendToken = async (
|
|
||||||
email: string,
|
|
||||||
user: { id: number; name: string }
|
|
||||||
) => {
|
|
||||||
const token = tokenGenerate(email, user.id)
|
|
||||||
|
|
||||||
const res = await sendToken(user.name, email, token)
|
|
||||||
|
|
||||||
if (res[0].statusCode != 202)
|
|
||||||
return new ApolloError("Couldn't send email", 'EMAILSENDERROR')
|
|
||||||
}
|
|
||||||
|
|
||||||
export { checkRightsAndResolve, getFormAuthor, genAndSendToken }
|
|
@ -1,208 +0,0 @@
|
|||||||
import { Answer as DbAnswer, PrismaClient, Form } from '@prisma/client'
|
|
||||||
import { ApolloError, UserInputError } from 'apollo-server-express'
|
|
||||||
|
|
||||||
import {
|
|
||||||
ChoisesQuestion,
|
|
||||||
Form as GraphqlForm,
|
|
||||||
FormSubmission,
|
|
||||||
InputQuestion,
|
|
||||||
MutationCreateFormArgs,
|
|
||||||
MutationFormSubmitArgs,
|
|
||||||
ServerAnswer,
|
|
||||||
Variant,
|
|
||||||
} from '../typeDefs/typeDefs.gen'
|
|
||||||
import {
|
|
||||||
CreateChoises,
|
|
||||||
FormConstructor,
|
|
||||||
UploadedChoisesQuestion,
|
|
||||||
UploadedInputQuestion,
|
|
||||||
UploadedQuestion,
|
|
||||||
} from './types'
|
|
||||||
import {
|
|
||||||
createDBForm,
|
|
||||||
getDBForm,
|
|
||||||
getDBFormsByUser,
|
|
||||||
submitDBAnswer,
|
|
||||||
getDBFormToSubmit,
|
|
||||||
} from '../db'
|
|
||||||
import {
|
|
||||||
validateCreateFormParameters,
|
|
||||||
validateSubmitAnswerParameters,
|
|
||||||
} from './validate'
|
|
||||||
|
|
||||||
const formatQuestions = (
|
|
||||||
choisesQuestions: (ChoisesQuestion & {
|
|
||||||
variants: Variant[]
|
|
||||||
})[],
|
|
||||||
inputQuestions: InputQuestion[]
|
|
||||||
) =>
|
|
||||||
[...choisesQuestions, ...inputQuestions].sort((a, b) => a.number - b.number)
|
|
||||||
|
|
||||||
const getForm = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
id: number,
|
|
||||||
user: { requesterId: number; ownerId: number }
|
|
||||||
): Promise<GraphqlForm> => {
|
|
||||||
try {
|
|
||||||
const dbForm = await getDBForm(db, id, user)
|
|
||||||
|
|
||||||
if (!dbForm) throw new ApolloError('Not found', 'NOTFOUND')
|
|
||||||
|
|
||||||
const form: GraphqlForm = {
|
|
||||||
author: dbForm.author,
|
|
||||||
dateCreated: dbForm.dateCreated.toString(),
|
|
||||||
id: dbForm.id,
|
|
||||||
questions: formatQuestions(
|
|
||||||
dbForm.choisesQuestions,
|
|
||||||
dbForm.inputQuestions
|
|
||||||
),
|
|
||||||
submissions:
|
|
||||||
user.ownerId == user.requesterId || !(dbForm.submissions.length == 0)
|
|
||||||
? dbForm.submissions.map((submission) => ({
|
|
||||||
user: submission.user,
|
|
||||||
answers: submission.answers,
|
|
||||||
date: submission.date.toString(),
|
|
||||||
id: submission.id,
|
|
||||||
}))
|
|
||||||
: null,
|
|
||||||
title: dbForm.title,
|
|
||||||
}
|
|
||||||
|
|
||||||
return form
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const getForms = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
userId: number
|
|
||||||
): Promise<GraphqlForm[]> => {
|
|
||||||
try {
|
|
||||||
const dbForms = await getDBFormsByUser(db, userId)
|
|
||||||
|
|
||||||
if (!dbForms) throw new ApolloError("Couldn't load forms", 'FETCHINGERROR')
|
|
||||||
|
|
||||||
const forms: GraphqlForm[] = dbForms.map((form) => ({
|
|
||||||
dateCreated: form.dateCreated.toString(),
|
|
||||||
id: form.id,
|
|
||||||
questions: [...form.choisesQuestions, ...form.inputQuestions],
|
|
||||||
submissions: form.submissions.map((submission) => ({
|
|
||||||
user: submission.user,
|
|
||||||
answers: submission.answers,
|
|
||||||
date: submission.date.toString(),
|
|
||||||
id: submission.id,
|
|
||||||
})),
|
|
||||||
title: form.title,
|
|
||||||
}))
|
|
||||||
|
|
||||||
return forms
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createFormFrom = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
params: MutationCreateFormArgs,
|
|
||||||
id: number
|
|
||||||
): Promise<ServerAnswer> => {
|
|
||||||
try {
|
|
||||||
const parsedQuestions = <UploadedQuestion[]>JSON.parse(params.questions)
|
|
||||||
|
|
||||||
await validateCreateFormParameters(params.title, parsedQuestions)
|
|
||||||
|
|
||||||
const newForm: FormConstructor = {
|
|
||||||
choisesQuestions: {
|
|
||||||
create: parsedQuestions.flatMap<CreateChoises>(
|
|
||||||
(uQuestion: UploadedChoisesQuestion | UploadedInputQuestion, index) =>
|
|
||||||
'type' in uQuestion
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
number: index,
|
|
||||||
title: uQuestion.title,
|
|
||||||
type: uQuestion.type,
|
|
||||||
variants: {
|
|
||||||
create: uQuestion.variants,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []
|
|
||||||
),
|
|
||||||
},
|
|
||||||
inputQuestions: {
|
|
||||||
create: parsedQuestions.flatMap<InputQuestion>(
|
|
||||||
(uQuestion: UploadedChoisesQuestion | UploadedInputQuestion, index) =>
|
|
||||||
!('type' in uQuestion)
|
|
||||||
? [{ number: index, title: uQuestion.title }]
|
|
||||||
: []
|
|
||||||
),
|
|
||||||
},
|
|
||||||
title: params.title,
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await createDBForm(db, newForm, id)
|
|
||||||
|
|
||||||
if (!res)
|
|
||||||
throw new ApolloError("Couldn't create new form", 'FORMCREATIONERROR')
|
|
||||||
|
|
||||||
return { success: true }
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const submitAnswer = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
{ answers, formId }: MutationFormSubmitArgs,
|
|
||||||
userId: number
|
|
||||||
): Promise<ServerAnswer> => {
|
|
||||||
try {
|
|
||||||
const form = await getDBFormToSubmit(db, formId)
|
|
||||||
if (!form) throw new UserInputError("Can't submit form")
|
|
||||||
|
|
||||||
form.submissions.forEach((submission) => {
|
|
||||||
if (submission.userId === userId)
|
|
||||||
throw new UserInputError("Can't submit same form more than once")
|
|
||||||
})
|
|
||||||
|
|
||||||
const parsedAnswers = <DbAnswer[]>JSON.parse(answers)
|
|
||||||
|
|
||||||
await validateSubmitAnswerParameters(
|
|
||||||
parsedAnswers,
|
|
||||||
formatQuestions(form.choisesQuestions, form.inputQuestions)
|
|
||||||
)
|
|
||||||
|
|
||||||
const res = await submitDBAnswer(db, userId, formId, parsedAnswers)
|
|
||||||
|
|
||||||
if (!res) throw new UserInputError("Can't submit form")
|
|
||||||
|
|
||||||
return { success: true }
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatForms = (
|
|
||||||
forms: (Form & {
|
|
||||||
choisesQuestions: (ChoisesQuestion & {
|
|
||||||
variants: Variant[]
|
|
||||||
})[]
|
|
||||||
inputQuestions: InputQuestion[]
|
|
||||||
submissions: (Omit<FormSubmission, 'date'> & { date: Date })[]
|
|
||||||
})[]
|
|
||||||
): GraphqlForm[] =>
|
|
||||||
forms.map<GraphqlForm>((form) => ({
|
|
||||||
dateCreated: form.dateCreated.toString(),
|
|
||||||
id: form.id,
|
|
||||||
questions: formatQuestions(form.choisesQuestions, form.inputQuestions),
|
|
||||||
submissions: form.submissions.map((submission) => ({
|
|
||||||
answers: submission.answers,
|
|
||||||
date: submission.date.toString(),
|
|
||||||
id: submission.id,
|
|
||||||
user: submission.user,
|
|
||||||
})),
|
|
||||||
title: form.title,
|
|
||||||
}))
|
|
||||||
|
|
||||||
export { createFormFrom, getForm, getForms, submitAnswer, formatForms }
|
|
@ -1,14 +0,0 @@
|
|||||||
import { checkRightsAndResolve, getFormAuthor, genAndSendToken } from './auth'
|
|
||||||
import { createFormFrom, getForm, getForms, submitAnswer } from './form'
|
|
||||||
import { findUserBy } from './user'
|
|
||||||
|
|
||||||
export {
|
|
||||||
checkRightsAndResolve,
|
|
||||||
createFormFrom,
|
|
||||||
findUserBy,
|
|
||||||
genAndSendToken,
|
|
||||||
getForm,
|
|
||||||
getFormAuthor,
|
|
||||||
getForms,
|
|
||||||
submitAnswer,
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
import sgMail from '@sendgrid/mail'
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') require('dotenv').config()
|
|
||||||
|
|
||||||
sgMail.setApiKey('' + process.env.SENDGRID_API_KEY)
|
|
||||||
|
|
||||||
const sendToken = (username: string, email: string, token: string) => {
|
|
||||||
return sgMail.send({
|
|
||||||
dynamicTemplateData: {
|
|
||||||
siteUrl: process.env.SITE_URL,
|
|
||||||
token: token,
|
|
||||||
username: username,
|
|
||||||
},
|
|
||||||
from: 'me@dmitriy.icu',
|
|
||||||
subject: 'Login link',
|
|
||||||
templateId: 'd-a9275a4437bf4dd2b9e858f3a57f85d5',
|
|
||||||
to: email,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export { sendToken }
|
|
@ -1,52 +0,0 @@
|
|||||||
import { ChoiseType } from '@prisma/client'
|
|
||||||
import {
|
|
||||||
ChoisesQuestion,
|
|
||||||
InputQuestion,
|
|
||||||
Variant,
|
|
||||||
} from '../typeDefs/typeDefs.gen'
|
|
||||||
import { JwtPayloadType } from '../types'
|
|
||||||
|
|
||||||
type ExpectedType = {
|
|
||||||
id: number
|
|
||||||
self: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ICheckRightsAndResolve<T> {
|
|
||||||
controller: T
|
|
||||||
expected: ExpectedType
|
|
||||||
user: JwtPayloadType | null
|
|
||||||
}
|
|
||||||
|
|
||||||
type CheckRightsAndResolve = <ReturnType, ControllerType extends Function>(
|
|
||||||
params: ICheckRightsAndResolve<ControllerType>
|
|
||||||
) => Promise<ReturnType>
|
|
||||||
|
|
||||||
type FormConstructor = {
|
|
||||||
choisesQuestions: { create: CreateChoises[] }
|
|
||||||
inputQuestions: { create: InputQuestion[] }
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateChoises = Omit<ChoisesQuestion, 'variants'> & {
|
|
||||||
variants: { create: Variant[] }
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploadedQuestion = {
|
|
||||||
title: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploadedChoisesQuestion = UploadedQuestion & {
|
|
||||||
type: ChoiseType
|
|
||||||
variants: Variant[]
|
|
||||||
}
|
|
||||||
|
|
||||||
type UploadedInputQuestion = UploadedQuestion
|
|
||||||
|
|
||||||
export {
|
|
||||||
CheckRightsAndResolve,
|
|
||||||
CreateChoises,
|
|
||||||
FormConstructor,
|
|
||||||
UploadedChoisesQuestion,
|
|
||||||
UploadedInputQuestion,
|
|
||||||
UploadedQuestion,
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
import { createDBUser, findDBUserBy } from '../db'
|
|
||||||
import { IFindUserParams } from '../db/types'
|
|
||||||
import { MutationRegisterArgs, User } from '../typeDefs/typeDefs.gen'
|
|
||||||
import { PrismaClient } from '@prisma/client'
|
|
||||||
import { ApolloError, UserInputError } from 'apollo-server-express'
|
|
||||||
import { formatForms } from './form'
|
|
||||||
import { formSubmitMutation, formsQuery } from 'resolvers/Form'
|
|
||||||
|
|
||||||
const createUser = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
{ email, name }: MutationRegisterArgs
|
|
||||||
): Promise<User> => {
|
|
||||||
try {
|
|
||||||
if (!email || !name)
|
|
||||||
throw new UserInputError(
|
|
||||||
'Provide full user information',
|
|
||||||
[!email ? [email] : [], !name ? [name] : []].flat()
|
|
||||||
)
|
|
||||||
|
|
||||||
const newUser = await createDBUser(db, { email, name })
|
|
||||||
|
|
||||||
if (!newUser)
|
|
||||||
throw new ApolloError("Couldn't create user", 'USERCREATIONERROR')
|
|
||||||
|
|
||||||
return newUser
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const findUserBy = async (
|
|
||||||
db: PrismaClient,
|
|
||||||
params: IFindUserParams
|
|
||||||
): Promise<User> => {
|
|
||||||
try {
|
|
||||||
const dbUser = await findDBUserBy(db, params)
|
|
||||||
|
|
||||||
if (!dbUser) throw new UserInputError('No such user')
|
|
||||||
|
|
||||||
const user: User = {
|
|
||||||
...dbUser,
|
|
||||||
forms: formatForms(dbUser.forms),
|
|
||||||
formSubmissions: dbUser.formSubmissions.map((formSubmission) => ({
|
|
||||||
...formSubmission,
|
|
||||||
date: formSubmission.date.toString(),
|
|
||||||
form: formSubmission.Form && {
|
|
||||||
...formSubmission.Form,
|
|
||||||
dateCreated: formSubmission.Form?.dateCreated.toString(),
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
|
|
||||||
return user
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { createUser, findUserBy }
|
|
@ -1,127 +0,0 @@
|
|||||||
'use strict'
|
|
||||||
import { UserInputError } from 'apollo-server-express'
|
|
||||||
import { Answer } from '@prisma/client'
|
|
||||||
import {
|
|
||||||
UploadedChoisesQuestion,
|
|
||||||
UploadedInputQuestion,
|
|
||||||
UploadedQuestion,
|
|
||||||
} from './types'
|
|
||||||
import { ChoisesQuestion, InputQuestion, Variant } from 'typeDefs/typeDefs.gen'
|
|
||||||
|
|
||||||
const choisesVariants = ['CHECK', 'CHOOSE', 'SELECT']
|
|
||||||
|
|
||||||
const validateCreateFormParameters = async (
|
|
||||||
title: string,
|
|
||||||
questions: UploadedQuestion[]
|
|
||||||
) => {
|
|
||||||
if (!title)
|
|
||||||
throw new UserInputError("Form title can't be empty", {
|
|
||||||
invalidArgs: ['title'],
|
|
||||||
})
|
|
||||||
|
|
||||||
questions.forEach(
|
|
||||||
(question: UploadedChoisesQuestion | UploadedInputQuestion) => {
|
|
||||||
if (!question.title)
|
|
||||||
throw new UserInputError("Question title can't be empty", {
|
|
||||||
invalidArgs: ['questions'],
|
|
||||||
})
|
|
||||||
|
|
||||||
if ('type' in question) {
|
|
||||||
if (!question.variants || question.variants.length < 1)
|
|
||||||
throw new UserInputError(
|
|
||||||
'Question with choises must have at least one answer variant',
|
|
||||||
{ invalidArgs: ['questions'] }
|
|
||||||
)
|
|
||||||
|
|
||||||
question.variants.forEach((variant) => {
|
|
||||||
if (!variant.text || variant.text.length < 1)
|
|
||||||
throw new UserInputError("Choises variant text can't be empty", {
|
|
||||||
invalidArgs: ['questions'],
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!choisesVariants.includes(question.type))
|
|
||||||
throw new UserInputError(
|
|
||||||
'Question with choises must be of one of supported types',
|
|
||||||
{ invalidArgs: ['questions'] }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const validateSubmitAnswerParameters = async (
|
|
||||||
answers: Answer[],
|
|
||||||
questions: (
|
|
||||||
| (ChoisesQuestion & {
|
|
||||||
variants: Variant[]
|
|
||||||
})
|
|
||||||
| InputQuestion
|
|
||||||
)[]
|
|
||||||
) => {
|
|
||||||
questions.forEach((question, questionIndex) => {
|
|
||||||
const answer = answers[questionIndex]
|
|
||||||
|
|
||||||
if (!answer)
|
|
||||||
throw new UserInputError('Every required question must have answer', {
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!answer.type)
|
|
||||||
throw new UserInputError('Type must be specified for answer', {
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
})
|
|
||||||
|
|
||||||
if (answer.type !== 'CHOISE' && answer.type !== 'INPUT')
|
|
||||||
throw new UserInputError('Answer must have supported type', {
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
})
|
|
||||||
|
|
||||||
if (answer.type === 'CHOISE' && !('type' in question))
|
|
||||||
throw new UserInputError(
|
|
||||||
`Answer ${questionIndex + 1} must be of 'INPUT' type`,
|
|
||||||
{
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (answer.type === 'INPUT' && 'type' in question)
|
|
||||||
throw new UserInputError(
|
|
||||||
`Answer ${questionIndex + 1} must be of 'CHOISE' type`,
|
|
||||||
{
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (answer.type === 'CHOISE' && answer.userChoise === null)
|
|
||||||
throw new UserInputError(
|
|
||||||
"Question of type 'CHOISE' must have choise number set",
|
|
||||||
{
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (answer.type === 'INPUT' && answer.userInput === null)
|
|
||||||
throw new UserInputError(
|
|
||||||
"Question of type 'INPUT' must have input string",
|
|
||||||
{
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
answer.userChoise !== null &&
|
|
||||||
(question as ChoisesQuestion).variants &&
|
|
||||||
answer.userChoise > (question as ChoisesQuestion).variants.length - 1
|
|
||||||
)
|
|
||||||
throw new UserInputError(
|
|
||||||
"Can't have chosen number bigger than amount of variants: " +
|
|
||||||
(question as ChoisesQuestion).variants.length,
|
|
||||||
{
|
|
||||||
invalidArgs: ['answers'],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export { validateCreateFormParameters, validateSubmitAnswerParameters }
|
|
209
src/db/index.ts
209
src/db/index.ts
@ -1,209 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client'
|
|
||||||
|
|
||||||
import { Answer, MutationRegisterArgs } from '../typeDefs/typeDefs.gen'
|
|
||||||
import { IFindUserParams } from './types'
|
|
||||||
import { FormConstructor } from '../controllers/types'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get form from DataBase
|
|
||||||
*
|
|
||||||
* @async
|
|
||||||
* @param db {PrismaClient} Prisma client object
|
|
||||||
* @param formId {number} Form ID
|
|
||||||
* @param getSubmissions {boolean} Set to true if want to also get form submissions
|
|
||||||
* @example
|
|
||||||
* const form = await getDBForm(db, id, true)
|
|
||||||
*/
|
|
||||||
const getDBForm = (
|
|
||||||
db: PrismaClient,
|
|
||||||
formId: number,
|
|
||||||
{
|
|
||||||
requesterId,
|
|
||||||
ownerId: ownerId,
|
|
||||||
}: {
|
|
||||||
requesterId: number
|
|
||||||
ownerId: number
|
|
||||||
}
|
|
||||||
) =>
|
|
||||||
db.form.findOne({
|
|
||||||
include: {
|
|
||||||
author: {
|
|
||||||
select: {
|
|
||||||
email: true,
|
|
||||||
id: true,
|
|
||||||
name: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
choisesQuestions: {
|
|
||||||
include: {
|
|
||||||
variants: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputQuestions: true,
|
|
||||||
submissions: {
|
|
||||||
include: {
|
|
||||||
user: true,
|
|
||||||
answers: true,
|
|
||||||
},
|
|
||||||
where:
|
|
||||||
requesterId != ownerId
|
|
||||||
? {
|
|
||||||
user: {
|
|
||||||
id: requesterId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
id: formId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all forms of user
|
|
||||||
* @param db {PrismaClient} Prisma client object
|
|
||||||
* @param id {number} User ID
|
|
||||||
* @example
|
|
||||||
* const forms = await getDBFormsByUser(db, userId)
|
|
||||||
*/
|
|
||||||
const getDBFormsByUser = (db: PrismaClient, id: number) =>
|
|
||||||
db.form.findMany({
|
|
||||||
include: {
|
|
||||||
choisesQuestions: {
|
|
||||||
include: {
|
|
||||||
variants: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputQuestions: true,
|
|
||||||
submissions: {
|
|
||||||
include: {
|
|
||||||
user: true,
|
|
||||||
answers: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
author: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const getDBFormAuthor = (db: PrismaClient, id: number) =>
|
|
||||||
db.form.findOne({
|
|
||||||
select: {
|
|
||||||
author: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const createDBUser = (
|
|
||||||
db: PrismaClient,
|
|
||||||
{ email, name }: MutationRegisterArgs
|
|
||||||
) =>
|
|
||||||
db.user.create({
|
|
||||||
data: { email, name },
|
|
||||||
})
|
|
||||||
|
|
||||||
const findDBUserBy = (db: PrismaClient, params: IFindUserParams) =>
|
|
||||||
db.user.findOne({
|
|
||||||
where: {
|
|
||||||
...params,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
forms: {
|
|
||||||
include: {
|
|
||||||
choisesQuestions: {
|
|
||||||
include: {
|
|
||||||
variants: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputQuestions: true,
|
|
||||||
submissions: {
|
|
||||||
include: {
|
|
||||||
user: true,
|
|
||||||
answers: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
formSubmissions: {
|
|
||||||
include: {
|
|
||||||
answers: true,
|
|
||||||
Form: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const createDBForm = (db: PrismaClient, form: FormConstructor, id: number) =>
|
|
||||||
db.form.create({
|
|
||||||
data: {
|
|
||||||
author: {
|
|
||||||
connect: { id },
|
|
||||||
},
|
|
||||||
...form,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const submitDBAnswer = (
|
|
||||||
db: PrismaClient,
|
|
||||||
userId: number,
|
|
||||||
formId: number,
|
|
||||||
formAnswers: Answer[]
|
|
||||||
) =>
|
|
||||||
db.formSubmission.create({
|
|
||||||
data: {
|
|
||||||
answers: {
|
|
||||||
create: formAnswers,
|
|
||||||
},
|
|
||||||
Form: {
|
|
||||||
connect: {
|
|
||||||
id: formId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
connect: {
|
|
||||||
id: userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const getDBFormToSubmit = async (db: PrismaClient, formId: number) =>
|
|
||||||
db.form.findOne({
|
|
||||||
where: {
|
|
||||||
id: formId,
|
|
||||||
},
|
|
||||||
select: {
|
|
||||||
choisesQuestions: {
|
|
||||||
include: {
|
|
||||||
variants: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
inputQuestions: true,
|
|
||||||
submissions: {
|
|
||||||
select: {
|
|
||||||
userId: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export {
|
|
||||||
createDBForm,
|
|
||||||
createDBUser,
|
|
||||||
findDBUserBy,
|
|
||||||
getDBForm,
|
|
||||||
getDBFormAuthor,
|
|
||||||
getDBFormsByUser,
|
|
||||||
submitDBAnswer,
|
|
||||||
getDBFormToSubmit,
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
import { PromiseReturnType } from '@prisma/client'
|
|
||||||
|
|
||||||
import { getDBForm } from '../db'
|
|
||||||
|
|
||||||
type FullForm = PromiseReturnType<typeof getDBForm>
|
|
||||||
|
|
||||||
interface IFindUserParams {
|
|
||||||
email?: string
|
|
||||||
id?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export { FullForm, IFindUserParams }
|
|
58
src/index.ts
58
src/index.ts
@ -1,58 +0,0 @@
|
|||||||
import express from 'express'
|
|
||||||
import expressJwt from 'express-jwt'
|
|
||||||
import resolvers from './resolvers'
|
|
||||||
import typeDefs from './typeDefs'
|
|
||||||
import { ApolloContextType, JwtPayloadType } from './types'
|
|
||||||
import { ApolloServer, makeExecutableSchema } from 'apollo-server-express'
|
|
||||||
import { PrismaClient } from '@prisma/client'
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') require('dotenv').config()
|
|
||||||
|
|
||||||
const app = express()
|
|
||||||
|
|
||||||
app.use(
|
|
||||||
expressJwt({
|
|
||||||
algorithms: ['HS256'],
|
|
||||||
credentialsRequired: false,
|
|
||||||
secret: '' + process.env.JWT_SECRET,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
const errorHandler: express.ErrorRequestHandler = (err, _, res, __) => {
|
|
||||||
if (err.name === 'UnauthorizedError') {
|
|
||||||
res.status(401).send('Invalid token')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
app.use(errorHandler)
|
|
||||||
|
|
||||||
const db = new PrismaClient()
|
|
||||||
|
|
||||||
const server = new ApolloServer({
|
|
||||||
context: async ({
|
|
||||||
req,
|
|
||||||
}: {
|
|
||||||
req: Request & {
|
|
||||||
user: JwtPayloadType
|
|
||||||
}
|
|
||||||
}): Promise<ApolloContextType> => {
|
|
||||||
const user = req.user || null
|
|
||||||
return {
|
|
||||||
db,
|
|
||||||
user,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
debug: false,
|
|
||||||
schema: makeExecutableSchema({
|
|
||||||
resolvers,
|
|
||||||
typeDefs,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
server.applyMiddleware({ app })
|
|
||||||
|
|
||||||
const port = process.env.BACKEND_PORT || 4000
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Server ready at http://localhost:${port}`)
|
|
||||||
})
|
|
16
src/main.ts
Normal file
16
src/main.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import express from "express"
|
||||||
|
import bodyParser from "body-parser"
|
||||||
|
|
||||||
|
import { router } from "./router"
|
||||||
|
import { logger } from "./middlewares"
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
app.use(bodyParser.json())
|
||||||
|
app.use(logger)
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
|
||||||
|
app.listen(3000, () => {
|
||||||
|
console.log("server is listening on port 3000")
|
||||||
|
})
|
8
src/middlewares.ts
Normal file
8
src/middlewares.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { RequestHandler } from "express"
|
||||||
|
|
||||||
|
const logger: RequestHandler = (req, res, next) => {
|
||||||
|
console.log(`sent ${req.method} request to ${req.hostname}${req.url}`)
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export { logger }
|
@ -1,136 +0,0 @@
|
|||||||
import {
|
|
||||||
AnswerResolvers,
|
|
||||||
Form,
|
|
||||||
MutationCreateFormArgs,
|
|
||||||
MutationFormSubmitArgs,
|
|
||||||
QueryFormArgs,
|
|
||||||
QuestionResolvers,
|
|
||||||
Resolver,
|
|
||||||
ServerAnswer,
|
|
||||||
} from '../typeDefs/typeDefs.gen'
|
|
||||||
import { ApolloContextType } from '../types'
|
|
||||||
import {
|
|
||||||
checkRightsAndResolve,
|
|
||||||
createFormFrom,
|
|
||||||
getForm,
|
|
||||||
getFormAuthor,
|
|
||||||
getForms,
|
|
||||||
submitAnswer,
|
|
||||||
} from '../controllers'
|
|
||||||
|
|
||||||
const formQuery: Resolver<Form, {}, ApolloContextType, QueryFormArgs> = async (
|
|
||||||
_,
|
|
||||||
{ id },
|
|
||||||
{ db, user }
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const ownerId = await getFormAuthor(db, id)
|
|
||||||
|
|
||||||
const getFormById = (requesterId: number) =>
|
|
||||||
getForm(db, id, { requesterId, ownerId })
|
|
||||||
|
|
||||||
return await checkRightsAndResolve({
|
|
||||||
controller: getFormById,
|
|
||||||
expected: {
|
|
||||||
id: 0,
|
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const formsQuery: Resolver<Form[], {}, ApolloContextType> = async (
|
|
||||||
_,
|
|
||||||
__,
|
|
||||||
{ db, user }
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const getFormsByUserId = (userId: number) => getForms(db, userId)
|
|
||||||
|
|
||||||
return await checkRightsAndResolve<
|
|
||||||
Form[],
|
|
||||||
(userId: number) => Promise<Form[] | null>
|
|
||||||
>({
|
|
||||||
controller: getFormsByUserId,
|
|
||||||
expected: {
|
|
||||||
id: 0,
|
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createFormMutation: Resolver<
|
|
||||||
ServerAnswer,
|
|
||||||
{},
|
|
||||||
ApolloContextType,
|
|
||||||
MutationCreateFormArgs
|
|
||||||
> = async (_, params, { db, user }) => {
|
|
||||||
const createNewForm = (id: number) => createFormFrom(db, params, id)
|
|
||||||
|
|
||||||
return await checkRightsAndResolve<
|
|
||||||
ServerAnswer,
|
|
||||||
(id: number) => Promise<ServerAnswer>
|
|
||||||
>({
|
|
||||||
controller: createNewForm,
|
|
||||||
expected: {
|
|
||||||
id: 0,
|
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const formSubmitMutation: Resolver<
|
|
||||||
ServerAnswer,
|
|
||||||
{},
|
|
||||||
ApolloContextType,
|
|
||||||
MutationFormSubmitArgs
|
|
||||||
> = async (_, params, { db, user }) => {
|
|
||||||
const submitNewAnswer = (userId: number) => submitAnswer(db, params, userId)
|
|
||||||
|
|
||||||
return await checkRightsAndResolve<
|
|
||||||
ServerAnswer,
|
|
||||||
(userId: number) => Promise<ServerAnswer>
|
|
||||||
>({
|
|
||||||
controller: submitNewAnswer,
|
|
||||||
expected: {
|
|
||||||
id: 0,
|
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const QuestionResolver: QuestionResolvers = {
|
|
||||||
__resolveType(obj: any) {
|
|
||||||
if (obj.type) {
|
|
||||||
return 'ChoisesQuestion'
|
|
||||||
}
|
|
||||||
return 'InputQuestion'
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnswerResolver: AnswerResolvers = {
|
|
||||||
__resolveType(obj) {
|
|
||||||
if (obj.type == 'CHOISE') return 'ChoiseAnswer'
|
|
||||||
if (obj.type == 'INPUT') return 'InputAnswer'
|
|
||||||
|
|
||||||
return null
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
AnswerResolver,
|
|
||||||
createFormMutation,
|
|
||||||
formQuery,
|
|
||||||
formsQuery,
|
|
||||||
formSubmitMutation,
|
|
||||||
QuestionResolver,
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
import {
|
|
||||||
checkRightsAndResolve,
|
|
||||||
findUserBy,
|
|
||||||
genAndSendToken,
|
|
||||||
} from '../controllers'
|
|
||||||
import { createUser } from '../controllers/user'
|
|
||||||
import {
|
|
||||||
MutationLoginArgs,
|
|
||||||
MutationRegisterArgs,
|
|
||||||
Resolver,
|
|
||||||
ServerAnswer,
|
|
||||||
User,
|
|
||||||
QueryUserArgs,
|
|
||||||
} from '../typeDefs/typeDefs.gen'
|
|
||||||
import { ApolloContextType } from '../types'
|
|
||||||
|
|
||||||
const loginMutation: Resolver<
|
|
||||||
ServerAnswer,
|
|
||||||
{},
|
|
||||||
ApolloContextType,
|
|
||||||
MutationLoginArgs
|
|
||||||
> = async (_, { email }, { db }) => {
|
|
||||||
try {
|
|
||||||
const user = await findUserBy(db, { email })
|
|
||||||
|
|
||||||
if (user instanceof Error) throw user // Needed to fix a strange error
|
|
||||||
|
|
||||||
await genAndSendToken(email, user)
|
|
||||||
|
|
||||||
return { success: true }
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const registerMutation: Resolver<
|
|
||||||
ServerAnswer,
|
|
||||||
{},
|
|
||||||
ApolloContextType,
|
|
||||||
MutationRegisterArgs
|
|
||||||
> = async (_, { email, name }, { db }) => {
|
|
||||||
try {
|
|
||||||
const user = await createUser(db, { email, name })
|
|
||||||
|
|
||||||
if (user instanceof Error) throw user // Needed to fix a strange error
|
|
||||||
|
|
||||||
await genAndSendToken(email, user)
|
|
||||||
|
|
||||||
return { success: true }
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const userQuery: Resolver<User, {}, ApolloContextType, QueryUserArgs> = async (
|
|
||||||
_,
|
|
||||||
{ id },
|
|
||||||
{ db, user }
|
|
||||||
) => {
|
|
||||||
try {
|
|
||||||
const findUserById = (id: number) => findUserBy(db, { id })
|
|
||||||
|
|
||||||
return await checkRightsAndResolve({
|
|
||||||
controller: findUserById,
|
|
||||||
expected: {
|
|
||||||
id: id || 0,
|
|
||||||
self: true,
|
|
||||||
},
|
|
||||||
user,
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { loginMutation, registerMutation, userQuery }
|
|
@ -1,32 +0,0 @@
|
|||||||
import { Resolvers } from '../typeDefs/typeDefs.gen'
|
|
||||||
import {
|
|
||||||
formQuery as form,
|
|
||||||
QuestionResolver as Question,
|
|
||||||
AnswerResolver as Answer,
|
|
||||||
formsQuery as forms,
|
|
||||||
createFormMutation as createForm,
|
|
||||||
formSubmitMutation as formSubmit,
|
|
||||||
} from './Form'
|
|
||||||
import {
|
|
||||||
loginMutation as login,
|
|
||||||
registerMutation as register,
|
|
||||||
userQuery as user,
|
|
||||||
} from './User'
|
|
||||||
|
|
||||||
const resolvers: Resolvers = {
|
|
||||||
Query: {
|
|
||||||
form,
|
|
||||||
forms,
|
|
||||||
user,
|
|
||||||
},
|
|
||||||
Mutation: {
|
|
||||||
login,
|
|
||||||
register,
|
|
||||||
createForm,
|
|
||||||
formSubmit,
|
|
||||||
},
|
|
||||||
Question,
|
|
||||||
Answer,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default resolvers
|
|
19
src/router/index.ts
Normal file
19
src/router/index.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import express from "express"
|
||||||
|
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/api/test",
|
||||||
|
(req: express.Request, res: express.Response) => {
|
||||||
|
return res.send(`Hello, ${req.query.name}`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
"/api/test",
|
||||||
|
async (req: express.Request, res: express.Response) => {
|
||||||
|
return res.send(`Hello, hidden ${req.body.name}`)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export { router }
|
@ -1,8 +0,0 @@
|
|||||||
import fs from 'fs'
|
|
||||||
import { gql } from 'apollo-server-express'
|
|
||||||
|
|
||||||
const typeDefs = gql(
|
|
||||||
fs.readFileSync(__dirname.concat('/typeDefs.gql'), { encoding: 'utf-8' })
|
|
||||||
)
|
|
||||||
|
|
||||||
export default typeDefs
|
|
@ -1,87 +0,0 @@
|
|||||||
type Query {
|
|
||||||
form(id: Int!): Form
|
|
||||||
forms: [Form!]!
|
|
||||||
user(id: Int): User
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mutation {
|
|
||||||
createForm(title: String!, questions: String!): serverAnswer
|
|
||||||
formSubmit(formId: Int!, answers: String!): serverAnswer
|
|
||||||
login(email: String!): serverAnswer
|
|
||||||
register(name: String!, email: String!): serverAnswer
|
|
||||||
}
|
|
||||||
|
|
||||||
type Form {
|
|
||||||
author: User
|
|
||||||
dateCreated: String!
|
|
||||||
id: Int!
|
|
||||||
questions: [Question!]
|
|
||||||
submissions: [FormSubmission!]
|
|
||||||
title: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Question {
|
|
||||||
number: Int!
|
|
||||||
title: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChoisesQuestion implements Question {
|
|
||||||
number: Int!
|
|
||||||
title: String!
|
|
||||||
type: ChoiseType!
|
|
||||||
variants: [Variant!]!
|
|
||||||
}
|
|
||||||
|
|
||||||
type Variant {
|
|
||||||
text: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type InputQuestion implements Question {
|
|
||||||
number: Int!
|
|
||||||
title: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
type FormSubmission {
|
|
||||||
user: User
|
|
||||||
answers: [Answer!]!
|
|
||||||
date: String!
|
|
||||||
id: Int!
|
|
||||||
form: Form
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Answer {
|
|
||||||
type: AnswerType!
|
|
||||||
}
|
|
||||||
|
|
||||||
type InputAnswer implements Answer {
|
|
||||||
type: AnswerType!
|
|
||||||
userInput: String
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChoiseAnswer implements Answer {
|
|
||||||
type: AnswerType!
|
|
||||||
userChoise: Int!
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ChoiseType {
|
|
||||||
CHECK
|
|
||||||
CHOOSE
|
|
||||||
SELECT
|
|
||||||
}
|
|
||||||
|
|
||||||
enum AnswerType {
|
|
||||||
CHOISE
|
|
||||||
INPUT
|
|
||||||
}
|
|
||||||
|
|
||||||
type User {
|
|
||||||
email: String!
|
|
||||||
forms: [Form!]
|
|
||||||
id: Int!
|
|
||||||
name: String!
|
|
||||||
formSubmissions: [FormSubmission!]
|
|
||||||
}
|
|
||||||
|
|
||||||
type serverAnswer {
|
|
||||||
success: Boolean!
|
|
||||||
}
|
|
11
src/types.ts
11
src/types.ts
@ -1,11 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client'
|
|
||||||
|
|
||||||
export type ApolloContextType = {
|
|
||||||
db: PrismaClient
|
|
||||||
user: JwtPayloadType | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export type JwtPayloadType = {
|
|
||||||
id: number
|
|
||||||
email: string
|
|
||||||
}
|
|
@ -1,16 +1,69 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||||
"module": "CommonJS" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
|
||||||
|
/* Basic Options */
|
||||||
|
// "incremental": true, /* Enable incremental compilation */
|
||||||
|
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
||||||
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
||||||
|
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||||
|
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||||
|
// "checkJs": true, /* Report errors in .js files. */
|
||||||
|
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||||
|
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||||
|
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
|
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||||
|
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||||
|
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||||
|
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
|
// "composite": true, /* Enable project compilation */
|
||||||
|
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||||
|
// "removeComments": true, /* Do not emit comments to output. */
|
||||||
|
// "noEmit": true, /* Do not emit outputs. */
|
||||||
|
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||||
|
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||||
|
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||||
|
|
||||||
|
/* Strict Type-Checking Options */
|
||||||
"strict": true /* Enable all strict type-checking options. */,
|
"strict": true /* Enable all strict type-checking options. */,
|
||||||
"outDir": "dist",
|
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||||
"noImplicitAny": false,
|
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||||
"moduleResolution": "Node",
|
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||||
"baseUrl": "src",
|
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||||
"incremental": true,
|
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||||
|
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||||
|
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||||
|
|
||||||
|
/* Additional Checks */
|
||||||
|
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
|
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||||
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||||
|
|
||||||
|
/* Module Resolution Options */
|
||||||
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||||
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
|
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||||
|
// "types": [], /* Type declaration files to be included in compilation. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
||||||
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
|
|
||||||
|
/* Source Map Options */
|
||||||
|
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||||
|
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||||
|
|
||||||
|
/* Experimental Options */
|
||||||
|
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||||
|
|
||||||
|
/* Advanced Options */
|
||||||
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
||||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||||
},
|
}
|
||||||
"include": ["src/**/*"]
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user