fixed duplicate views bug
This commit is contained in:
parent
b3915b7f90
commit
f6bb23a3bf
12
Dockerfile
12
Dockerfile
@ -18,6 +18,8 @@ ENV PORT 3000
|
||||
RUN apt-get update -q \
|
||||
&& apt-get install -yqq \
|
||||
curl \
|
||||
ant \
|
||||
default-jdk \
|
||||
git \
|
||||
gcc \
|
||||
make \
|
||||
@ -47,8 +49,7 @@ WORKDIR /opt/tellform
|
||||
# when the local package.json file changes.
|
||||
# Add npm package.json
|
||||
COPY package.json /opt/tellform/package.json
|
||||
RUN npm install --production
|
||||
RUN mv ./node_modules ./node_modules.tmp && mv ./node_modules.tmp ./node_modules && npm install
|
||||
RUN npm install
|
||||
|
||||
# Add bower.json
|
||||
COPY bower.json /opt/tellform/bower.json
|
||||
@ -62,5 +63,8 @@ COPY ./server.js /opt/tellform/server.js
|
||||
COPY ./.env /opt/tellform/.env
|
||||
COPY ./scripts/create_admin.js /opt/tellform/scripts/create_admin.js
|
||||
|
||||
# Run TellForm server
|
||||
CMD npm start
|
||||
# Run Development TellForm server
|
||||
COPY ./dev_entrypoint.sh /dev_entrypoint.sh
|
||||
RUN chmod +x /dev_entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/dev_entrypoint.sh"]
|
||||
@ -19,6 +19,8 @@ ENV BASE_URL tellform.com
|
||||
RUN apt-get update -q \
|
||||
&& apt-get install -yqq \
|
||||
curl \
|
||||
ant \
|
||||
default-jdk \
|
||||
git \
|
||||
gcc \
|
||||
make \
|
||||
|
||||
174
INSTALLATION_INSTRUCTIONS.md
Normal file
174
INSTALLATION_INSTRUCTIONS.md
Normal file
@ -0,0 +1,174 @@
|
||||
TellForm Installation Instructions
|
||||
==================================
|
||||
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Local Deployment with Docker](#local-deployment-with-docker)
|
||||
- [AWS AMI Deployment](#aws-ami-deployment)
|
||||
|
||||
|
||||
## Local deployment with Docker
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Make you sure have the following packages and versions on your machine:
|
||||
```
|
||||
"node": ">=6.11.2"
|
||||
"npm": ">=3.3.6"
|
||||
"bower": ">=1.8.0"
|
||||
"grunt-cli": ">=1.2.0"
|
||||
"grunt": ">=0.4.5"
|
||||
"docker": ">=17.06.0-ce"
|
||||
"docker-compose": ">=1.14.0"
|
||||
```
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```
|
||||
$ npm install
|
||||
```
|
||||
|
||||
### Prepare .env file:
|
||||
Create `.env` file at project root folder. Fill in `MAILER_SERVICE_PROVIDER`, `MAILER_EMAIL_ID`, `MAILER_PASSWORD` and `MAILER_FROM`.
|
||||
```
|
||||
APP_NAME=TellForm
|
||||
BASE_URL=localhost:3000
|
||||
PORT=3000
|
||||
DB_PORT_27017_TCP_ADDR=tellform-mongo
|
||||
REDIS_DB_PORT_6379_TCP_ADDR=tellform-redis
|
||||
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
|
||||
```
|
||||
|
||||
### Build docker image
|
||||
|
||||
```
|
||||
$ docker-compose build
|
||||
```
|
||||
|
||||
### Run docker containers with docker-compose
|
||||
|
||||
Create and start mongo & redis docker container:
|
||||
```
|
||||
$ docker-compose up
|
||||
```
|
||||
|
||||
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.
|
||||
@ -40,6 +40,9 @@ var ButtonSchema = new Schema({
|
||||
});
|
||||
|
||||
var VisitorDataSchema = new Schema({
|
||||
socketId: {
|
||||
type: String
|
||||
},
|
||||
referrer: {
|
||||
type: String
|
||||
},
|
||||
|
||||
@ -12,14 +12,14 @@ module.exports = function (io, socket) {
|
||||
var visitorsData = {};
|
||||
|
||||
var saveVisitorData = function (data, cb){
|
||||
|
||||
Form.findById(data.formId, function(err, form) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
console.error(err);
|
||||
throw new Error(errorHandler.getErrorMessage(err));
|
||||
}
|
||||
|
||||
var newVisitor = {
|
||||
socketId: data.socketId,
|
||||
referrer: data.referrer,
|
||||
lastActiveField: data.lastActiveField,
|
||||
timeElapsed: data.timeElapsed,
|
||||
@ -37,35 +37,37 @@ module.exports = function (io, socket) {
|
||||
throw new Error(errorHandler.getErrorMessage(formSaveErr));
|
||||
}
|
||||
|
||||
delete visitorsData[socket.id];
|
||||
|
||||
if(cb){
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
io.on('connection', function(current_socket) {
|
||||
|
||||
// a user has visited our page - add them to the visitorsData object
|
||||
current_socket.on('form-visitor-data', function(data) {
|
||||
current_socket.id = data.formId;
|
||||
visitorsData[current_socket.id] = data;
|
||||
visitorsData[current_socket.id].isSaved = false;
|
||||
if (data.isSubmitted) {
|
||||
saveVisitorData(data, function () {
|
||||
visitorsData[current_socket.id].isSaved = true;
|
||||
});
|
||||
}
|
||||
visitorsData[current_socket.id] = data;
|
||||
visitorsData[current_socket.id].socketId = current_socket.id;
|
||||
visitorsData[current_socket.id].isSaved = false;
|
||||
if (data.isSubmitted && !data.isSaved) {
|
||||
visitorsData[current_socket.id].isSaved = true;
|
||||
saveVisitorData(data, function() {
|
||||
console.log("\n\n\n\n\ncurrent_socket.id: "+current_socket.id);
|
||||
current_socket.disconnect(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
current_socket.on('disconnect', function() {
|
||||
var data = visitorsData[current_socket.id];
|
||||
if(data && !data.isSubmitted && !data.isSaved) {
|
||||
data.isSaved = true;
|
||||
saveVisitorData(data);
|
||||
saveVisitorData(data, function() {
|
||||
delete visitorsData[current_socket.id];
|
||||
});
|
||||
} else {
|
||||
delete visitorsData[current_socket.id];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
1
config/env/all.js
vendored
1
config/env/all.js
vendored
@ -61,7 +61,6 @@ module.exports = {
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
||||
// To set the cookie in a specific domain uncomment the following
|
||||
// setting:
|
||||
//domain: process.env.COOKIE_SESSION_URL || process.env.BASE_URL || '.tellform.com'
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
10
dev_entrypoint.sh
Normal file
10
dev_entrypoint.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
line=$(head -n 1 /etc/hosts)
|
||||
echo "$line tellform.dev $(hostname)" >> /etc/hosts
|
||||
|
||||
# Restart sendmail
|
||||
service sendmail restart
|
||||
|
||||
# Run Server
|
||||
npm start
|
||||
@ -1,22 +1,22 @@
|
||||
version: "3"
|
||||
services:
|
||||
tellform:
|
||||
image: tellform/production:no_subdomains
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: dockerfile
|
||||
image: tellform
|
||||
ports:
|
||||
- 3000:3000
|
||||
- 8080:80
|
||||
links:
|
||||
- redis:redis-db
|
||||
- mongo:db
|
||||
environment:
|
||||
- BASE_URL=localhost
|
||||
- DB_1_PORT_27017_TCP_ADDR=mongo
|
||||
- REDIS_DB_PORT_6379_TCP_ADDR=redis
|
||||
redis:
|
||||
image: redis:alpine
|
||||
- tellform-redis:redis-db
|
||||
- tellform-mongo:db
|
||||
env_file:
|
||||
- .env
|
||||
tellform-redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379
|
||||
mongo:
|
||||
image: mongo:latest
|
||||
tellform-mongo:
|
||||
image: mongo
|
||||
ports:
|
||||
- 27017
|
||||
|
||||
3211
public/dist/application.js
vendored
3211
public/dist/application.js
vendored
File diff suppressed because one or more lines are too long
4
public/dist/application.min.css
vendored
4
public/dist/application.min.css
vendored
File diff suppressed because one or more lines are too long
10
public/dist/application.min.js
vendored
10
public/dist/application.min.js
vendored
File diff suppressed because one or more lines are too long
429
public/dist/form-application.js
vendored
429
public/dist/form-application.js
vendored
File diff suppressed because one or more lines are too long
4
public/dist/form-application.min.js
vendored
4
public/dist/form-application.min.js
vendored
File diff suppressed because one or more lines are too long
@ -221,7 +221,7 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||
});
|
||||
});
|
||||
});
|
||||
}else {
|
||||
} else {
|
||||
setTimeout(function() {
|
||||
if (document.querySelectorAll('.activeField .focusOn')[0]) {
|
||||
//FIXME: DAVID: Figure out how to set focus without scroll movement in HTML Dom
|
||||
@ -232,7 +232,10 @@ angular.module('view-form').directive('submitFormDirective', ['$http', 'TimeCoun
|
||||
});
|
||||
}
|
||||
|
||||
SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed());
|
||||
//Only send analytics data if form has not been submitted
|
||||
if(!$scope.myform.submitted){
|
||||
SendVisitorData.send($scope.myform, getActiveField(), TimeCounter.getTimeElapsed());
|
||||
}
|
||||
};
|
||||
|
||||
$rootScope.nextField = $scope.nextField = function(){
|
||||
|
||||
@ -4,10 +4,22 @@
|
||||
// Create the Socket.io wrapper service
|
||||
function Socket($timeout, $window) {
|
||||
|
||||
var service;
|
||||
var service = {
|
||||
socket: null
|
||||
};
|
||||
|
||||
// Connect to Socket.io server
|
||||
function connect(url) {
|
||||
// Connect to TellForm Socket.io server
|
||||
function connect() {
|
||||
var url = '';
|
||||
if($window.socketUrl && $window.socketPort){
|
||||
url = window.location.protocol + '//' + $window.socketUrl + ':' + $window.socketPort;
|
||||
} else if ($window.socketUrl){
|
||||
url = window.location.protocol + '//' + $window.socketUrl;
|
||||
} else if ($window.socketPort){
|
||||
url = window.location.protocol + '//' + window.location.hostname + ':' + $window.socketPort;
|
||||
} else {
|
||||
url = window.location.protocol + '//' + window.location.hostname;
|
||||
}
|
||||
service.socket = io(url, {'transports': ['websocket', 'polling']});
|
||||
}
|
||||
|
||||
@ -36,6 +48,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
service = {
|
||||
connect: connect,
|
||||
emit: emit,
|
||||
@ -44,19 +58,6 @@
|
||||
socket: null
|
||||
};
|
||||
|
||||
console.log($window.socketUrl);
|
||||
var url = '';
|
||||
if($window.socketUrl && $window.socketPort){
|
||||
url = window.location.protocol + '//' + $window.socketUrl + ':' + $window.socketPort;
|
||||
} else if ($window.socketUrl){
|
||||
url = window.location.protocol + '//' + $window.socketUrl;
|
||||
} else if ($window.socketPort){
|
||||
url = window.location.protocol + '//' + window.location.hostname + ':' + $window.socketPort;
|
||||
} else {
|
||||
url = window.location.protocol + '//' + window.location.hostname;
|
||||
}
|
||||
connect(url);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
@ -12,16 +12,13 @@ angular.module('view-form').config(['$stateProvider',
|
||||
Forms: 'Forms',
|
||||
myForm: function (Forms, $q, $state, $stateParams) {
|
||||
var deferred = $q.defer();
|
||||
console.log(Forms.get({formId: $stateParams.formId}).$promise);
|
||||
return Forms.get({formId: $stateParams.formId}).$promise.then(function(data) {
|
||||
console.log(data);
|
||||
return data;
|
||||
}, function(reason) {
|
||||
console.log(reason);
|
||||
console.error(reason);
|
||||
$state.go('unauthorizedFormAccess');
|
||||
return deferred.reject({redirectTo: 'unauthorizedFormAccess'});
|
||||
});
|
||||
//return Forms.get({formId: $stateParams.formId}).$promise;
|
||||
}
|
||||
},
|
||||
controller: 'SubmitFormController',
|
||||
|
||||
@ -55,6 +55,8 @@
|
||||
country: geoData.country_name
|
||||
}
|
||||
};
|
||||
|
||||
console.log('sending form-visitor-data');
|
||||
Socket.emit('form-visitor-data', visitorData);
|
||||
}
|
||||
|
||||
@ -63,6 +65,11 @@
|
||||
if (!Socket.socket) {
|
||||
Socket.connect();
|
||||
}
|
||||
|
||||
Socket.on('disconnect', function(){
|
||||
console.log("reconnected to socket");
|
||||
Socket.connect();
|
||||
});
|
||||
}
|
||||
|
||||
var service = {
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// Create the Socket.io wrapper service
|
||||
angular
|
||||
.module('core')
|
||||
.factory('Socket', Socket);
|
||||
|
||||
Socket.$inject = ['$timeout', '$window'];
|
||||
|
||||
function Socket($timeout, $window) {
|
||||
// Connect to Socket.io server
|
||||
function connect(url) {
|
||||
service.socket = io(url, {'transports': ['websocket', 'polling']});
|
||||
}
|
||||
|
||||
// Wrap the Socket.io 'emit' method
|
||||
function emit(eventName, data) {
|
||||
if (service.socket) {
|
||||
service.socket.emit(eventName, data);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the Socket.io 'on' method
|
||||
function on(eventName, callback) {
|
||||
if (service.socket) {
|
||||
service.socket.on(eventName, function (data) {
|
||||
$timeout(function () {
|
||||
callback(data);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap the Socket.io 'removeListener' method
|
||||
function removeListener(eventName) {
|
||||
if (service.socket) {
|
||||
service.socket.removeListener(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
var service = {
|
||||
connect: connect,
|
||||
emit: emit,
|
||||
on: on,
|
||||
removeListener: removeListener,
|
||||
socket: null
|
||||
};
|
||||
|
||||
connect(window.location.protocol+'//'+window.location.hostname);
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
}());
|
||||
@ -123,7 +123,10 @@
|
||||
<h5>{{ 'BACKGROUND_COLOR' | translate }}</h5>
|
||||
</div>
|
||||
<div class="field-input col-sm-6">
|
||||
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.backgroundColor" ng-style="{ 'background-color': myform.design.colors.backgroundColor }"/>
|
||||
<input class="form-control" colorpicker="hex" type="text"
|
||||
ng-model="myform.design.colors.backgroundColor"
|
||||
ng-pattern="/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/"
|
||||
ng-style="{ 'background-color': myform.design.colors.backgroundColor }"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -133,7 +136,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field-input col-sm-6">
|
||||
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.questionColor" ng-style="{ 'background-color': myform.design.colors.questionColor }"/>
|
||||
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.questionColor" ng-pattern="/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/"ng-style="{ 'background-color': myform.design.colors.questionColor }"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -143,7 +146,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field-input col-sm-6">
|
||||
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.answerColor" ng-style="{ 'background-color': myform.design.colors.answerColor }"/>
|
||||
<input class="form-control" colorpicker="hex" type="text" ng-model="myform.design.colors.answerColor" ng-pattern="/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/" ng-style="{ 'background-color': myform.design.colors.answerColor }"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -155,6 +158,7 @@
|
||||
<div class="field-input col-sm-6">
|
||||
<input class="form-control" colorpicker="hex" type="text"
|
||||
ng-model="myform.design.colors.buttonColor"
|
||||
ng-pattern="/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/"
|
||||
ng-style="{ 'background-color': myform.design.colors.buttonColor }"/>
|
||||
</div>
|
||||
</div>
|
||||
@ -166,6 +170,7 @@
|
||||
<div class="field-input col-sm-6">
|
||||
<input class="form-control" colorpicker="hex" type="text"
|
||||
ng-model="myform.design.colors.buttonTextColor"
|
||||
ng-pattern="/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/"
|
||||
ng-style="{ 'background-color': myform.design.colors.buttonTextColor }"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user