From f7fab04e542b50e1be008073da354a75de9ddee6 Mon Sep 17 00:00:00 2001 From: wodka Date: Mon, 29 Jul 2019 00:54:58 +0200 Subject: [PATCH] add form and user schema --- api/src/forms/schemas/button.schema.ts | 20 +++ api/src/forms/schemas/field.option.schema.ts | 16 ++ api/src/forms/schemas/field.schema.ts | 66 ++++++++ api/src/forms/schemas/form.schema.ts | 151 +++++++++++++++++++ api/src/forms/schemas/logic.jump.schema.ts | 36 +++++ api/src/forms/schemas/rating.field.schema.ts | 30 ++++ api/src/forms/schemas/visitor.data.schema.ts | 35 +++++ api/src/users/schemas/user.schema.ts | 80 ++++++++++ 8 files changed, 434 insertions(+) create mode 100644 api/src/forms/schemas/button.schema.ts create mode 100644 api/src/forms/schemas/field.option.schema.ts create mode 100644 api/src/forms/schemas/field.schema.ts create mode 100644 api/src/forms/schemas/form.schema.ts create mode 100644 api/src/forms/schemas/logic.jump.schema.ts create mode 100644 api/src/forms/schemas/rating.field.schema.ts create mode 100644 api/src/forms/schemas/visitor.data.schema.ts create mode 100644 api/src/users/schemas/user.schema.ts diff --git a/api/src/forms/schemas/button.schema.ts b/api/src/forms/schemas/button.schema.ts new file mode 100644 index 00000000..5b4d1230 --- /dev/null +++ b/api/src/forms/schemas/button.schema.ts @@ -0,0 +1,20 @@ +import * as mongoose from 'mongoose'; + +export const ButtonSchema = new mongoose.Schema({ + url: { + type: String, + match: [/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/], + }, + action: String, + text: String, + bgColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#5bc0de' + }, + color: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#ffffff' + } +}); diff --git a/api/src/forms/schemas/field.option.schema.ts b/api/src/forms/schemas/field.option.schema.ts new file mode 100644 index 00000000..aedb04d5 --- /dev/null +++ b/api/src/forms/schemas/field.option.schema.ts @@ -0,0 +1,16 @@ +import * as mongoose from 'mongoose'; + +export const FieldOptionSchema = new mongoose.Schema({ + option_id: { + type: Number + }, + + option_title: { + type: String + }, + + option_value: { + type: String, + trim: true + } +}); diff --git a/api/src/forms/schemas/field.schema.ts b/api/src/forms/schemas/field.schema.ts new file mode 100644 index 00000000..22a08212 --- /dev/null +++ b/api/src/forms/schemas/field.schema.ts @@ -0,0 +1,66 @@ +import * as mongoose from 'mongoose'; +import {RatingFieldSchema} from "./rating.field.schema" +import {FieldOptionSchema} from "./field.option.schema" +import {LogicJumpSchema} from "./logic.jump.schema" + +export const FieldSchema = new mongoose.Schema({ + isSubmission: { + type: Boolean, + default: false + }, + submissionId: { + type: mongoose.Schema.Types.ObjectId + }, + title: { + type: String, + trim: true + }, + description: { + type: String, + default: '' + }, + + logicJump: LogicJumpSchema, + + ratingOptions: RatingFieldSchema, + fieldOptions: [FieldOptionSchema], + + required: { + type: Boolean, + default: true + }, + disabled: { + type: Boolean, + default: false + }, + + deletePreserved: { + type: Boolean, + default: false + }, + validFieldTypes: { + type: [String] + }, + fieldType: { + type: String, + enum: [ + 'textfield', + 'date', + 'email', + 'legal', + 'textarea', + 'link', + 'statement', + 'dropdown', + 'rating', + 'radio', + 'hidden', + 'yes_no', + 'number' + ] + }, + fieldValue: { + type: mongoose.Schema.Types.Mixed, + default: '' + } +}); diff --git a/api/src/forms/schemas/form.schema.ts b/api/src/forms/schemas/form.schema.ts new file mode 100644 index 00000000..18ab73a8 --- /dev/null +++ b/api/src/forms/schemas/form.schema.ts @@ -0,0 +1,151 @@ +import * as mongoose from 'mongoose'; +import {VisitorDataSchema} from "./visitor.data.schema" +import {ButtonSchema} from "./button.schema" +import {FieldSchema} from "./field.schema" + +export const FormSchema = new mongoose.Schema({ + title: { + type: String, + trim: true, + required: 'Form Title cannot be blank' + }, + language: { + type: String, + enum: ['en', 'fr', 'es', 'it', 'de'], + default: 'en', + required: 'Form must have a language' + }, + analytics:{ + gaCode: { + type: String + }, + visitors: [VisitorDataSchema] + }, + form_fields: { + type: [FieldSchema], + default: [] + }, + admin: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: 'Form must have an Admin' + }, + startPage: { + showStart:{ + type: Boolean, + default: false + }, + introTitle:{ + type: String, + default: 'Welcome to Form' + }, + introParagraph:{ + type: String + }, + introButtonText:{ + type: String, + default: 'Start' + }, + buttons:[ButtonSchema] + }, + endPage: { + showEnd:{ + type: Boolean, + default: false + }, + title:{ + type: String, + default: 'Thank you for filling out the form' + }, + paragraph:{ + type: String + }, + buttonText:{ + type: String, + default: 'Go back to Form' + }, + buttons:[ButtonSchema] + }, + + selfNotifications: { + fromField: { + type: String + }, + toEmails: { + type: String + }, + subject: { + type: String + }, + htmlTemplate: { + type: String + }, + enabled: { + type: Boolean, + default: false + } + }, + + respondentNotifications: { + toField: { + type: String + }, + fromEmails: { + type: String, + match: [/.+\@.+\..+/, 'Please fill a valid email address'] + }, + subject: { + type: String, + default: 'OhMyForm: Thank you for filling out this OhMyForm' + }, + htmlTemplate: { + type: String, + default: 'Hello,

We’ve received your submission.

Thank you & have a nice day!', + }, + enabled: { + type: Boolean, + default: false + } + }, + + showFooter: { + type: Boolean, + default: true + }, + + isLive: { + type: Boolean, + default: true + }, + + design: { + colors: { + backgroundColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#fff' + }, + questionColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#333' + }, + answerColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#333' + }, + buttonColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#fff' + }, + buttonTextColor: { + type: String, + match: [/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/], + default: '#333' + } + }, + font: String + } +}); diff --git a/api/src/forms/schemas/logic.jump.schema.ts b/api/src/forms/schemas/logic.jump.schema.ts new file mode 100644 index 00000000..9f3b7a83 --- /dev/null +++ b/api/src/forms/schemas/logic.jump.schema.ts @@ -0,0 +1,36 @@ +import * as mongoose from 'mongoose'; + +export const LogicJumpSchema = new mongoose.Schema({ + expressionString: { + type: String, + enum: [ + 'field == static', + 'field != static', + 'field > static', + 'field >= static', + 'field <= static', + 'field < static', + 'field contains static', + 'field !contains static', + 'field begins static', + 'field !begins static', + 'field ends static', + 'field !ends static' + ] + }, + fieldA: { + type: mongoose.Schema.Types.ObjectId, + ref: 'FormField' + }, + valueB: { + type: mongoose.Schema.Types.String + }, + jumpTo: { + type: mongoose.Schema.Types.ObjectId, + ref: 'FormField' + }, + enabled: { + type: mongoose.Schema.Types.Boolean, + default: false + } +}); diff --git a/api/src/forms/schemas/rating.field.schema.ts b/api/src/forms/schemas/rating.field.schema.ts new file mode 100644 index 00000000..e6b63b50 --- /dev/null +++ b/api/src/forms/schemas/rating.field.schema.ts @@ -0,0 +1,30 @@ +import * as mongoose from 'mongoose'; + +export const RatingFieldSchema = new mongoose.Schema({ + steps: { + type: Number, + min: 1, + max: 10 + }, + shape: { + type: String, + enum: [ + 'Heart', + 'Star', + 'thumbs-up', + 'thumbs-down', + 'Circle', + 'Square', + 'Check Circle', + 'Smile Outlined', + 'Hourglass', + 'bell', + 'Paper Plane', + 'Comment', + 'Trash' + ] + }, + validShapes: { + type: [String] + } +}); diff --git a/api/src/forms/schemas/visitor.data.schema.ts b/api/src/forms/schemas/visitor.data.schema.ts new file mode 100644 index 00000000..ee2e83eb --- /dev/null +++ b/api/src/forms/schemas/visitor.data.schema.ts @@ -0,0 +1,35 @@ +import * as mongoose from 'mongoose'; + +export const VisitorDataSchema = new mongoose.Schema({ + socketId: { + type: String + }, + referrer: { + type: String + }, + filledOutFields: { + type: [mongoose.Schema.Types.ObjectId] + }, + timeElapsed: { + type: Number + }, + isSubmitted: { + type: Boolean + }, + language: { + type: String, + enum: ['en', 'fr', 'es', 'it', 'de'], + default: 'en', + }, + ipAddr: { + type: String + }, + deviceType: { + type: String, + enum: ['desktop', 'phone', 'tablet', 'other'], + default: 'other' + }, + userAgent: { + type: String + } +}); diff --git a/api/src/users/schemas/user.schema.ts b/api/src/users/schemas/user.schema.ts new file mode 100644 index 00000000..7cd7cd47 --- /dev/null +++ b/api/src/users/schemas/user.schema.ts @@ -0,0 +1,80 @@ +import * as mongoose from 'mongoose'; + +export const UserSchema = new mongoose.Schema({ + firstName: { + type: String, + trim: true, + default: '' + }, + lastName: { + type: String, + trim: true, + default: '' + }, + email: { + type: String, + trim: true, + lowercase: true, + unique: 'Account already exists with this email', + match: [ + /^(([^<>()\[\]\\.,;:\s@']+(\.[^<>()\[\]\\.,;:\s@']+)*)|('.+'))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, + 'Please fill a valid email address' + ], + required: [true, 'Email is required'] + }, + username: { + type: String, + unique: true, + lowercase: true, + match: [ + /^[a-zA-Z0-9\-]+$/, + 'Username can only contain alphanumeric characters and \'-\'' + ], + required: [true, 'Username is required'] + }, + passwordHash: { + type: String, + default: '' + }, + salt: { + type: String + }, + provider: { + type: String, + default: 'local' + }, + roles: { + type: [{ + type: String, + enum: ['user', 'admin', 'superuser'] + }], + default: ['user'] + }, + language: { + type: String, + enum: ['en', 'fr', 'es', 'it', 'de'], + default: 'en', + }, + lastModified: { + type: Date + }, + created: { + type: Date, + default: Date.now + }, + + /* For reset password */ + resetPasswordToken: { + type: String + }, + resetPasswordExpires: { + type: Date + }, + token: String, + apiKey: { + type: String, + unique: true, + index: true, + sparse: true + } +});