fixed editField bug

This commit is contained in:
David Baldwynn 2017-10-18 17:18:18 -07:00
parent 60abe5a227
commit 154fddff75
20 changed files with 152 additions and 249 deletions

View File

@ -7,8 +7,6 @@
FROM phusion/baseimage:0.9.19
MAINTAINER David Baldwynn <team@tellform.com>
#FROM node:6.11.4-alpine
# Install Utilities
RUN apt-get update -q \
&& apt-get install -yqq \
@ -55,9 +53,7 @@ COPY ./scripts/create_admin.js /opt/tellform/scripts/create_admin.js
# when the local package.json file changes.
# Add npm package.json
COPY ./package.json /opt/tellform/package.json
RUN npm install --quiet
COPY ./start.sh /start.sh
RUN npm install --only=production --quiet
# Run TellForm server
CMD ["/start.sh"]
CMD ["node", "server.js"]

View File

@ -54,7 +54,6 @@ exports.createSubmission = function(req, res) {
}
var submission = new FormSubmission({
form: req.body._id,
title: req.body.title,
form_fields: req.body.form_fields,
timeElapsed: timeElapsed,
percentageComplete: req.body.percentageComplete,
@ -96,6 +95,7 @@ exports.listSubmissions = function(req, res) {
* Create a new form
*/
exports.create = function(req, res) {
debugger;
if(!req.body.form){
return res.status(401).send({
@ -107,13 +107,14 @@ exports.create = function(req, res) {
form.admin = req.user._id;
form.save(function(err) {
debugger;
if (err) {
return res.status(500).send({
message: errorHandler.getErrorMessage(err)
});
}
res.json(form);
return res.json(form);
});
};

View File

@ -12,10 +12,6 @@ var mongoose = require('mongoose'),
* Form Submission Schema
*/
var FormSubmissionSchema = new Schema({
title: {
type: String
},
form_fields: [FieldSchema],
form: {
@ -58,6 +54,19 @@ FormSubmissionSchema.pre('save', function (next) {
if(this.form_fields[i].fieldType === 'dropdown'){
this.form_fields[i].fieldValue = this.form_fields[i].fieldValue.option_value;
}
delete form_fields[i].validFieldTypes;
delete form_fields[i].disabled;
delete form_fields[i].required;
delete form_fields[i].isSubmission;
delete form_fields[i].title;
delete form_fields[i].fieldOptions;
delete form_fields[i].ratingOptions;
delete form_fields[i].logicJump;
delete form_fields[i].description;
delete form_fields[i].created;
delete form_fields[i].lastModified;
delete form_fields[i].deletePreserved;
}
next();
});
@ -68,6 +77,17 @@ FormSubmissionSchema.path('form_fields', {
form_fields[i].isSubmission = true;
form_fields[i]._id = new mongoose.mongo.ObjectID();
delete form_fields[i].validFieldTypes;
delete form_fields[i].disabled;
delete form_fields[i].required;
delete form_fields[i].isSubmission;
delete form_fields[i].title;
delete form_fields[i].fieldOptions;
delete form_fields[i].ratingOptions;
delete form_fields[i].logicJump;
delete form_fields[i].description;
delete form_fields[i].created;
delete form_fields[i].lastModified;
delete form_fields[i].deletePreserved;
}

21
config/env/all.js vendored
View File

@ -22,9 +22,28 @@ module.exports = {
signupDisabled: (process.env.SIGNUP_DISABLED === 'TRUE'),
enableClusterMode: (process.env.ENABLE_CLUSTER_MODE === 'TRUE'),
baseUrl: '',
baseUrl: process.env.BASE_URL || 'localhost',
tempUserCollection: 'temporary_users',
mailer: {
from: process.env.MAILER_FROM || 'testing@'+process.env.SPARKPOST_SANDBOX_DOMAIN || 'no-reply@tellform.com',
options: process.env.MAILER_SMTP_HOST ? { //Uses custom SMTP if MAILER_SMTP_HOST is set
host: process.env.MAILER_SMTP_HOST || '',
port: process.env.MAILER_SMTP_PORT || 465,
secure: process.env.MAILER_SMTP_SECURE || true,
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''
}
} : {
service: process.env.MAILER_SERVICE_PROVIDER || '',
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''
}
}
},
subdomainsDisabled: (process.env.SUBDOMAINS_DISABLED === 'TRUE'),
//Sentry DSN Client Key

View File

@ -31,23 +31,5 @@ module.exports = {
css: 'public/dist/application.min.css',
js: 'public/dist/application.min.js',
form_js: 'public/dist/form-application.min.js'
},
mailer: {
from: process.env.MAILER_FROM || 'testing@'+process.env.SPARKPOST_SANDBOX_DOMAIN || 'no-reply@tellform.com',
options: process.env.MAILER_SMTP_HOST ? { //Uses custom SMTP if MAILER_SMTP_HOST is set
host: process.env.MAILER_SMTP_HOST || '',
port: process.env.MAILER_SMTP_PORT || 465,
secure: process.env.MAILER_SMTP_SECURE || true,
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''
}
} : {
service: process.env.MAILER_SERVICE_PROVIDER || '',
auth: {
user: process.env.MAILER_EMAIL_ID || '',
pass: process.env.MAILER_PASSWORD || ''
}
}
}
};

View File

@ -280,16 +280,16 @@ module.exports = function(db) {
// Log it
client.captureError(err);
/*if(process.env.NODE_ENV === 'production'){
if(process.env.NODE_ENV === 'production'){
res.status(500).render('500', {
error: 'Internal Server Error'
});
} else {*/
error: 'Internal Server Error'
});
} else {
// Error page
res.status(500).render('500', {
error: err.stack
});
//}
}
});
// Assume 404 since no middleware responded

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

BIN
design/tellform_mascot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -1995,6 +1995,14 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope
}
};
// Return all user's Forms
$scope.findAll = function() {
GetForms.query(function(_forms){
$scope.myforms = _forms;
});
};
/*
** DeleteModal Functions
*/
@ -2029,13 +2037,6 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope
}
};
// Return all user's Forms
$scope.findAll = function() {
GetForms.query(function(_forms){
$scope.myforms = _forms;
});
};
//Modal functions
$scope.openCreateModal = function(){
if(!$scope.showCreateModal){
@ -2513,27 +2514,10 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
rows: []
};
var submissions = $scope.myform.submissions || [];
//Iterate through form's submissions
for(var i = 0; i < submissions.length; i++){
for(var x = 0; x < submissions[i].form_fields.length; x++){
if(submissions[i].form_fields[x].fieldType === 'dropdown'){
submissions[i].form_fields[x].fieldValue = submissions[i].form_fields[x].fieldValue.option_value;
}
//var oldValue = submissions[i].form_fields[x].fieldValue || '';
//submissions[i].form_fields[x] = _.merge(defaultFormFields, submissions[i].form_fields);
//submissions[i].form_fields[x].fieldValue = oldValue;
}
submissions[i].selected = false;
}
$scope.table.rows = submissions;
var initController = function(){
$http({
method: 'GET',
url: '/someUrl'
url: '/forms'+$scope.myform._id+'/submissions'
}).then(function successCallback(response) {
var defaultFormFields = _.cloneDeep($scope.myform.form_fields);
@ -2556,6 +2540,8 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
});
};
initController();
/*
** Analytics Functions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,18 @@
/*Modal overlay (for lightbox effect)*/
.overlay {
position: fixed;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.5);
z-index: 10;
}
.overlay.submitform {
background-color: rgb(256,256,256);
background-color: rgba(256,256,256,0.8);
}
.form-item .title-row > .list-group-item-heading {
color: #34628a;

View File

@ -1,12 +1,13 @@
'use strict';
// Forms controller
angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'GetForms', 'CurrentForm', '$http', '$uibModal',
function($rootScope, $scope, $stateParams, $state, GetForms, CurrentForm, $http, $uibModal) {
angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope', '$stateParams', '$state', 'GetForms', 'CurrentForm', '$http', '$uibModal', 'myForms',
function($rootScope, $scope, $stateParams, $state, GetForms, CurrentForm, $http, $uibModal, myForms) {
$scope = $rootScope;
$scope.forms = {};
$scope.showCreateModal = false;
$scope.myforms = myForms
$rootScope.languageRegExp = {
regExp: /[@!#$%^&*()\-+={}\[\]|\\/'";:`.,~№?<>]+/i,
@ -49,13 +50,6 @@ angular.module('forms').controller('ListFormsController', ['$rootScope', '$scope
}
};
// Return all user's Forms
$scope.findAll = function() {
GetForms.query(function(_forms){
$scope.myforms = _forms;
});
};
//Modal functions
$scope.openCreateModal = function(){
if(!$scope.showCreateModal){

View File

@ -32,7 +32,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
/*
** EditModal Functions
*/
$scope.openEditModal = function(curr_field){
$scope.openEditModal = function(curr_field, isEdit, field_index){
$scope.editFieldModal = $uibModal.open({
animation: true,
templateUrl: 'editFieldModal.html',
@ -41,6 +41,8 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
$scope.field = curr_field;
$scope.showLogicJump = false;
$scope.isEdit = isEdit;
// decides whether field options block will be shown (true for dropdown and radio fields)
$scope.showAddOptions = function (field){
if(field.fieldType === 'dropdown' || field.fieldType === 'checkbox' || field.fieldType === 'radio'){
@ -67,13 +69,13 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
];
// add new option to the field
$scope.addOption = function(currField){
if(currField.fieldType === 'checkbox' || currField.fieldType === 'dropdown' || currField.fieldType === 'radio'){
if(!currField.fieldOptions){
currField.fieldOptions = [];
$scope.addOption = function(){
if($scope.field.fieldType === 'checkbox' || $scope.field.fieldType === 'dropdown' || $scope.field.fieldType === 'radio'){
if(!$scope.field.fieldOptions){
$scope.field.fieldOptions = [];
}
var lastOptionID = currField.fieldOptions.length+1;
var lastOptionID = $scope.field.fieldOptions.length+1;
// new option's id
@ -84,17 +86,17 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
// put new option into fieldOptions array
currField.fieldOptions.push(newOption);
$scope.field.fieldOptions.push(newOption);
}
};
// delete particular option
$scope.deleteOption = function (currField, option){
if(currField.fieldType === 'checkbox' || currField.fieldType === 'dropdown' || currField.fieldType === 'radio'){
for(var i = 0; i < currField.fieldOptions.length; i++){
if(currField.fieldOptions[i].option_id === option.option_id){
$scope.deleteOption = function (option){
if($scope.field.fieldType === 'checkbox' || $scope.field.fieldType === 'dropdown' || $scope.field.fieldType === 'radio'){
for(var i = 0; i < $scope.field.fieldOptions.length; i++){
if($scope.field.fieldOptions[i].option_id === option.option_id){
currField.fieldOptions.splice(i, 1);
$scope.field.fieldOptions.splice(i, 1);
break;
}
}
@ -119,8 +121,8 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
// decides whether field options block will be shown (true for dropdown and radio fields)
$scope.showRatingOptions = function (field){
if(field.fieldType === 'rating'){
$scope.showRatingOptions = function (){
if($scope.field.fieldType === 'rating'){
return true;
} else {
return false;
@ -128,11 +130,16 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
};
$scope.saveField = function(){
if($scope.isEdit){
$scope.myform.form_fields[field_index] = $scope.field;
} else {
$scope.myform.form_fields.push(curr_field);
}
$scope.myform.form_fields.push(curr_field);
$scope.$parent.update(false, $scope.$parent.myform, true, true, function(){
$uibModalInstance.close();
});
};
$scope.cancel = function(){
$uibModalInstance.close();
@ -268,7 +275,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
** Field CRUD Methods
*/
// Add a new field
$scope.addNewField = function(modifyForm, fieldType){
$scope.addNewField = function(fieldType){
// increment lastAddedID counter
$scope.addField.lastAddedID++;
var fieldTitle = fieldType;
@ -307,12 +314,7 @@ angular.module('forms').directive('editFormDirective', ['$rootScope', 'FormField
});
}
if(modifyForm){
//Add newField to form_fields array
$scope.myform.form_fields.push(newField);
}
$scope.openEditModal(newField);
$scope.openEditModal(newField, false, $scope.myform.form_fields.length);
};
// decides whether field options block will be shown (true for dropdown and radio fields)

View File

@ -16,27 +16,10 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
rows: []
};
var submissions = $scope.myform.submissions || [];
//Iterate through form's submissions
for(var i = 0; i < submissions.length; i++){
for(var x = 0; x < submissions[i].form_fields.length; x++){
if(submissions[i].form_fields[x].fieldType === 'dropdown'){
submissions[i].form_fields[x].fieldValue = submissions[i].form_fields[x].fieldValue.option_value;
}
//var oldValue = submissions[i].form_fields[x].fieldValue || '';
//submissions[i].form_fields[x] = _.merge(defaultFormFields, submissions[i].form_fields);
//submissions[i].form_fields[x].fieldValue = oldValue;
}
submissions[i].selected = false;
}
$scope.table.rows = submissions;
var initController = function(){
$http({
method: 'GET',
url: '/someUrl'
url: '/forms'+$scope.myform._id+'/submissions'
}).then(function successCallback(response) {
var defaultFormFields = _.cloneDeep($scope.myform.form_fields);
@ -59,6 +42,8 @@ angular.module('forms').directive('editSubmissionsFormDirective', ['$rootScope',
});
};
initController();
/*
** Analytics Functions

View File

@ -146,8 +146,6 @@
</div>
</div>
</script>
<!-- Edit StartPage Modal Dialog Template -->
@ -291,8 +289,6 @@
</div>
</div>
</script>
<!-- Edit Field Modal Dialog Template -->
@ -312,34 +308,34 @@
<div class="row"><br></div>
<div class="row description" ng-hide="showRatingOptions(field)">
<div class="row description" ng-hide="showRatingOptions()">
<div class="col-md-12 bold">{{ 'QUESTION_DESCRIPTION' | translate }}</div>
<div class="col-md-12">
<textarea type="text" class="form-control" ng-model="field.description" name="description{{field._id}}"value="{{field.description}}"></textarea>
</div>
</div>
<div class="row" ng-show="showAddOptions(field)"><br></div>
<div class="row options" ng-if="showAddOptions(field)">
<div class="row" ng-show="showAddOptions()"><br></div>
<div class="row options" ng-if="showAddOptions()">
<div class="col-md-4 col-xs-12">{{ 'OPTIONS' | translate }}</div>
<div class="col-md-8 col-xs-12">
<div ng-repeat="option in field.fieldOptions track by option.option_id" class="row">
<input type="text" name="{{option.option_value}}{{field._id}}" ng-model="option.option_value" class="col-xs-5">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteOption(field, option)" class="col-xs-3">
<a class="btn btn-danger btn-mini right" type="button" ng-click="deleteOption(option)" class="col-xs-3">
<i class="fa fa-trash-o"></i>
</a>
</div>
<div class="row">
<button class="btn btn-primary btn-small col-md-offset-0 col-md-6 col-sm-4 col-sm-offset-4 col-xs-6 col-xs-offset-6" type="button" ng-click="addOption(field)">
<button class="btn btn-primary btn-small col-md-offset-0 col-md-6 col-sm-4 col-sm-offset-4 col-xs-6 col-xs-offset-6" type="button" ng-click="addOption()">
<i class="icon-plus icon-white"></i> {{ 'ADD_OPTION' | translate }}
</button>
</div>
</div>
</div>
<div class="row" ng-show="showRatingOptions(field)"><br></div>
<div class="row" ng-if="showRatingOptions(field)">
<div class="row" ng-show="showRatingOptions()"><br></div>
<div class="row" ng-if="showRatingOptions()">
<div class="col-md-9 col-sm-9">{{ 'NUM_OF_STEPS' | translate }}</div>
<div class="col-md-3 col-sm-3">
<input style="width:100%" type="number"
@ -483,7 +479,7 @@
</div>
<div class="preview-field-panel col-md-6 hidden-sm hidden-xs">
<form class="public-form"ss>
<form class="public-form">
<field-directive field="field" validate="false" class="preview-field">
</field-directive>
</form>
@ -545,7 +541,7 @@
<div class="col-xs-12 field-row" ng-repeat="field in myform.form_fields track by $id($index)" ng-if="!field.deletePreserved">
<div class="col-xs-10">
<div class="panel panel-default" ng-click="openEditModal(field)">
<div class="panel panel-default" ng-click="openEditModal(field, true, $index)">
<div class="panel-heading">
<div class="row">
<span class="col-xs-1" ng-switch="field.fieldType">

View File

@ -25,7 +25,7 @@
</div>
</script>
<section data-ng-controller="ListFormsController as ctrl" data-ng-init="findAll()" class="container">
<section class="container">
<br>
<div class="row">
<div ng-click="openCreateModal()" class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item create-new">
@ -71,7 +71,8 @@
<div data-ng-repeat="form in myforms"
class="col-xs-6 col-xs-offset-3 col-sm-4 col-sm-offset-1 col-md-3 col-md-offset-1 form-item container"
ng-class="{'paused': !form.isLive}">
ng-class="{'paused': !form.isLive}"
ng-clkc="goToWithId('viewForm.create', form._id)">
<div class="row">
<span class="pull-right">

View File

@ -8,7 +8,21 @@ angular.module('forms').config(['$stateProvider',
$stateProvider.
state('listForms', {
url: '/forms',
templateUrl: 'modules/forms/admin/views/list-forms.client.view.html'
templateUrl: 'modules/forms/admin/views/list-forms.client.view.html',
resolve: {
Forms: 'GetForms',
myForms: function (GetForms, $q) {
var deferred = $q.defer();
GetForms.query(function(forms){
deferred.resolve(forms);
});
return deferred.promise;
}
},
controller: 'ListFormsController',
controllerAs: 'ctrl'
}).state('submitForm', {
url: '/forms/:formId',
templateUrl: '/static/form_modules/forms/base/views/submit-form.client.view.html',

View File

@ -3,6 +3,11 @@
* Module dependencies.
*/
if(!process.env.NODE_ENV){
process.env.NODE_ENV = 'development';
}
require('dotenv').config()
require('events').EventEmitter.prototype._maxListeners = 0;
@ -65,4 +70,4 @@ process.on('uncaughtException', function (err) {
console.error((new Date()).toUTCString() + ' uncaughtException:', err.message);
console.error(err.stack);
process.exit(1);
});
});

View File

@ -17,12 +17,11 @@ Nginx installed by following the first two steps of the [How To Install Nginx on
Docker installed by following the steps of the [How To Install and Use Docker on Ubuntu 16.04 tutorial](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-16-04)
## Step 1 - Install Libraries
### Install dependencies
## Step 1 - Fetch Docker-Compose Files
```
$ npm install
$ curl -L github.com/tellform/tellform/stable/blob/docker-compose.yml
$ curl -L github.com/tellform/tellform/stable/blob/.env
```
### Prepare .env file:
@ -52,119 +51,7 @@ $ docker-compose build
Create and start mongo & redis docker container:
```
$ docker-compose up
$ docker-compose up -d
```
Your application should run on port 3000 or the port you specified in your .env file, so in your browser just go to [http://localhost:3000](http://localhost:3000)
## AWS AMI Deployment
### Prerequisites
Instructions here are tested on an Amazon Linux AMI. First, set up your fresh new AMI by setting the environment variables:
```
$ sudo vim /etc/environment
LANG=en_US.utf-8
LC_ALL=en_US.utf-8
```
Next, update and install build tools:
```
$ sudo yum update -y
$ sudo yum groupinstall "Development Tools" -y
```
### Install docker
```
$ sudo yum install -y docker
$ sudo service docker start
```
To ensure docker can be run without `sudo` each time:
```
$ sudo usermod -a -G docker ec2-user
$ logout
```
SSH back in, and test that `docker info` runs successfully.
### Install docker-compose
```
$ sudo -i
$ curl -L https://github.com/docker/compose/releases/download/1.15.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ logout
```
### Clone our repo
```
$ git clone https://github.com/datagovsg/formsg.git
```
### Prepare .env file
The `.env` file for remote deployment (or production) is slightly different from that of local deployment.
Create `.env` file at project root folder. Similarly, fill in `MAILER_SERVICE_PROVIDER`, `MAILER_EMAIL_ID`, `MAILER_PASSWORD` and `MAILER_FROM`. Note that now you have to fill in the public IP of your instance in `BASE_URL`.
```
APP_NAME=FormSG
APP_DESC=
APP_KEYWORDS=
NODE_ENV=production
BASE_URL=<PUBLIC IP OF YOUR INSTANCE>
PORT=4545
DB_PORT_27017_TCP_ADDR=<PRIVATE IP OF YOUR MONGODB HOST>
REDIS_DB_PORT_6379_TCP_ADDR=formsg-redis
username=formsg_admin
MAILER_SERVICE_PROVIDER=<TO-FILL-IN>
MAILER_EMAIL_ID=<TO-FILL-IN>
MAILER_PASSWORD=<TO-FILL-IN>
MAILER_FROM=<TO-FILL-IN>
SIGNUP_DISABLED=false
SUBDOMAINS_DISABLED=true
DISABLE_CLUSTER_MODE=true
RAVEN_DSN=
PRERENDER_TOKEN=
COVERALLS_REPO_TOKEN=
```
### Install npm, bower and grunt
```
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.32.0/install.sh | bash
$ . ~/.nvm/nvm.sh
$ nvm install 6.11.2
$ npm install -g bower
$ npm install -g grunt-cli
$ npm install grunt
```
### Install dependencies
```
$ npm install --production
```
### Build docker image
```
$ docker-compose -f docker-compose-production.yml build
```
### Run docker containers
```
$ docker run -d -p 27017:27017 -v /data/db:/data/db --name formsg-mongo mongo
$ docker-compose -f docker-compose-production.yml up
```
Note that unlike dev, mongo container is run separately from compose. Hence `docker-compose down` does not take down the mongo container each time. Your application should run on the default port 80, so in your browser just go to your public IP.
## Support
Please contact David Baldwynn (team@tellform.com) for any details.
Your application should run at the BASE_URL you specified on port 443.