From c7cd78bc45f9de7bb9bb2b5b52138cb661914c2f Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Wed, 25 Jan 2017 21:11:42 +0200 Subject: [PATCH 01/10] Add link to join slack --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 32fb50d9c..bd37a69f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ Before contributing, please review this guide. ## Got a Question or Problem? -* Join our Slack and ask us at #sparksystem channel +* [Join our Slack](https://www.hamsterpad.com/chat/midburnos) and ask us at #sparksystem channel * Email: **tech@midburn.org** ## Found an Issue? From 8ab50b8438e9a99efcbbb7610ce9a8409eb7c4db Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Mon, 6 Feb 2017 23:45:50 +0200 Subject: [PATCH 02/10] Add eslint --- .eslintignore | 2 ++ .eslintrc | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 11 +++------ server.js | 14 +++++------ 4 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..9d93d3db7 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +public/gentelella/**/*.js +*.min.js \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..68b730e7e --- /dev/null +++ b/.eslintrc @@ -0,0 +1,67 @@ +{ + "parser": "babel-eslint", + "plugins": [ + "flowtype" + ], + "rules": { + "flowtype/boolean-style": [ + 2, + "boolean" + ], + "flowtype/define-flow-type": 1, + "flowtype/delimiter-dangle": [ + 2, + "never" + ], + "flowtype/generic-spacing": [ + 2, + "never" + ], + "flowtype/no-primitive-constructor-types": 2, + "flowtype/no-weak-types": 2, + "flowtype/object-type-delimiter": [ + 2, + "comma" + ], + "flowtype/require-parameter-type": 2, + "flowtype/require-return-type": [ + 2, + "always", + { + "annotateUndefined": "never" + } + ], + "flowtype/require-valid-file-annotation": 2, + "flowtype/semi": [ + 2, + "always" + ], + "flowtype/space-after-type-colon": [ + 2, + "always" + ], + "flowtype/space-before-generic-bracket": [ + 2, + "never" + ], + "flowtype/space-before-type-colon": [ + 2, + "never" + ], + "flowtype/type-id-match": [ + 2, + "^([A-Z][a-z0-9]+)+Type$" + ], + "flowtype/union-intersection-spacing": [ + 2, + "always" + ], + "flowtype/use-flow-type": 1, + "flowtype/valid-syntax": 1 + }, + "settings": { + "flowtype": { + "onlyFilesWithFlowAnnotation": false + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 8b524fddc..4f35497e0 100644 --- a/package.json +++ b/package.json @@ -1,32 +1,24 @@ { "name": "spark", - "//version": [ "the version number is available to the scripts in the npm_package_version environment variable", "this is part of the deployment proess, so it is important to update the version number", "version name corresponds to the github release name / tag name - https://github.com/Midburn/Spark/releases" ], "version": "1.1.0", - "private": true, "scripts": { "start": "node server.js", "test": "mocha \"routes/*test.js\" ", - "//devops": "Generic deployment / devops commands, used from .travis.yml, see /docs/development/releases-and-deployment.md", - "//log": "send a generic log notification to slack", "log": "curl -X POST -g $npm_config_webhook --data-urlencode 'payload={\"channel\": \"'\"#${npm_config_channel:-sparksystem-log}\"'\", \"username\": \"'\"${npm_config_username:-bot}\"'\", \"text\": \"'\"${npm_config_text}\"'\", \"icon_emoji\": \"'\"${npm_config_emoji:-ghost}\"'\"}'", - "//build": "builds the deployment package", "build": "touch \"${npm_config_file}\" && tar -czf \"${npm_config_file}\" . --exclude=.github* --exclude=.idea* --exclude=.git* --exclude=dev.sqlite3 --exclude=opsworks.js --exclude=*.tar.gz --exclude=vagrant --exclude=docs --exclude=.travis.yml --exclude=*.iml && echo \"created build package: ${npm_config_file}\"", - "//upload": "uploads the deployment package to slack and returns the package private url", "upload": "curl -F \"file=@${npm_config_file}\" -F \"filename=${npm_config_file}\" -F \"token=${npm_config_token}\" \"${npm_config_url:-https://slack.com/api/files.upload}\" | jq -r .file.url_private > \"${npm_config_file}.slack_url\"", - "//download": "download a deployment package from private slack url", "download": "curl -H \"Authorization: Bearer ${npm_config_token}\" -g \"${npm_config_url}\" -o \"${npm_config_file}\"", - "//deploy": "prepare the directory of an extracted deployment package", "deploy": "echo SPARK_DEPLOYMENT_TIME=\\\"$(date \"+%F %T\")\\\" >> .env" }, @@ -81,9 +73,12 @@ "devDependencies": { "babel-cli": "^6.18.0", "babel-core": "^6.21.0", + "babel-eslint": "^7.1.1", "babel-loader": "^6.2.10", "babel-preset-react": "^6.16.0", "chai": "*", + "eslint": "^3.15.0", + "eslint-plugin-flowtype": "^2.30.0", "mocha": "^3.2.0", "sqlite3": "^3.1.8", "supertest": "^2.0.1" diff --git a/server.js b/server.js index 9835da44c..a4cc46d16 100644 --- a/server.js +++ b/server.js @@ -61,9 +61,9 @@ function onError(error) { throw error; } - var bind = typeof port === 'string' - ? 'Pipe ' + port - : 'Port ' + port; + var bind = typeof port === 'string' ? + 'Pipe ' + port : + 'Port ' + port; // handle specific listen errors with friendly messages switch (error.code) { @@ -86,8 +86,8 @@ function onError(error) { function onListening() { var addr = server.address(); - var bind = typeof addr === 'string' - ? 'pipe ' + addr - : 'port ' + addr.port; + var bind = typeof addr === 'string' ? + 'pipe ' + addr : + 'port ' + addr.port; debug('Listening on ' + bind); -} +} \ No newline at end of file From b0daaea1ea177313c0a4d2ea2c81bdd4d823b7e0 Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Tue, 7 Feb 2017 00:01:19 +0200 Subject: [PATCH 03/10] Ignore bulk of errors for now --- .eslintrc | 67 ---------------------------------------------------- .eslintrc.js | 28 ++++++++++++++++++++++ package.json | 4 +++- 3 files changed, 31 insertions(+), 68 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 68b730e7e..000000000 --- a/.eslintrc +++ /dev/null @@ -1,67 +0,0 @@ -{ - "parser": "babel-eslint", - "plugins": [ - "flowtype" - ], - "rules": { - "flowtype/boolean-style": [ - 2, - "boolean" - ], - "flowtype/define-flow-type": 1, - "flowtype/delimiter-dangle": [ - 2, - "never" - ], - "flowtype/generic-spacing": [ - 2, - "never" - ], - "flowtype/no-primitive-constructor-types": 2, - "flowtype/no-weak-types": 2, - "flowtype/object-type-delimiter": [ - 2, - "comma" - ], - "flowtype/require-parameter-type": 2, - "flowtype/require-return-type": [ - 2, - "always", - { - "annotateUndefined": "never" - } - ], - "flowtype/require-valid-file-annotation": 2, - "flowtype/semi": [ - 2, - "always" - ], - "flowtype/space-after-type-colon": [ - 2, - "always" - ], - "flowtype/space-before-generic-bracket": [ - 2, - "never" - ], - "flowtype/space-before-type-colon": [ - 2, - "never" - ], - "flowtype/type-id-match": [ - 2, - "^([A-Z][a-z0-9]+)+Type$" - ], - "flowtype/union-intersection-spacing": [ - 2, - "always" - ], - "flowtype/use-flow-type": 1, - "flowtype/valid-syntax": 1 - }, - "settings": { - "flowtype": { - "onlyFilesWithFlowAnnotation": false - } - } -} \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..d9a9d4ce2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,28 @@ +module.exports = { + "extends": "standard", + "plugins": [ + "standard", + "promise" + ], + "rules": { + // Used in tests + "no-undef": ["off"], + + // Style + "semi": ["off"], + "indent": ["off"], + "eol-last": ["off"], + "quotes": ["off"], + "operator-linebreak": ["off"], + "space-before-function-paren": ["off"], + "spaced-comment": ["off"], + "brace-style": ["off"], + "padded-blocks": ["off"], + "camelcase": ["off"], + "space-infix-ops": ["off"], + "comma-spacing": ["off"], + "no-trailing-spaces": ["off"], + "key-spacing": ["off"], + "block-spacing": ["off"], + } +}; \ No newline at end of file diff --git a/package.json b/package.json index 4f35497e0..fb56d8e65 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,9 @@ "babel-preset-react": "^6.16.0", "chai": "*", "eslint": "^3.15.0", - "eslint-plugin-flowtype": "^2.30.0", + "eslint-config-standard": "^6.2.1", + "eslint-plugin-promise": "^3.4.0", + "eslint-plugin-standard": "^2.0.1", "mocha": "^3.2.0", "sqlite3": "^3.1.8", "supertest": "^2.0.1" From 30addf7eba5a500ccaeb3e8e742c739fe0450b75 Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Tue, 7 Feb 2017 00:03:05 +0200 Subject: [PATCH 04/10] Add npm target --- package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fb56d8e65..278c8ba5e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,9 @@ "//download": "download a deployment package from private slack url", "download": "curl -H \"Authorization: Bearer ${npm_config_token}\" -g \"${npm_config_url}\" -o \"${npm_config_file}\"", "//deploy": "prepare the directory of an extracted deployment package", - "deploy": "echo SPARK_DEPLOYMENT_TIME=\\\"$(date \"+%F %T\")\\\" >> .env" + "deploy": "echo SPARK_DEPLOYMENT_TIME=\\\"$(date \"+%F %T\")\\\" >> .env", + "//lint": "runs static analysis using eslint", + "lint": "./node_modules/.bin/eslint ." }, "dependencies": { "babel-core": "^6.21.0", @@ -85,4 +87,4 @@ "sqlite3": "^3.1.8", "supertest": "^2.0.1" } -} +} \ No newline at end of file From 5761faf18669b2cec3a58536819a56a6c0352ff5 Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Tue, 7 Feb 2017 00:10:36 +0200 Subject: [PATCH 05/10] Add 'npm lint' as a precusor task to 'npm test' --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 278c8ba5e..2031a2320 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "private": true, "scripts": { "start": "node server.js", + "pretest": "npm run lint", "test": "mocha \"routes/*test.js\" ", "//devops": "Generic deployment / devops commands, used from .travis.yml, see /docs/development/releases-and-deployment.md", "//log": "send a generic log notification to slack", From 2d9d87ea8998407529121cd9b674d149ac26d3fb Mon Sep 17 00:00:00 2001 From: Ron Gross Date: Tue, 7 Feb 2017 12:02:03 +0200 Subject: [PATCH 06/10] Fix lint errors --- .eslintrc.js | 3 + app.js | 26 +-- config/default.js | 4 +- libs/logger.js | 64 ++++--- libs/passport.js | 107 ++++++----- libs/payment.js | 15 +- libs/security.js | 15 +- libs/user_role.js | 16 +- models/npo_member.js | 18 +- public/scripts/camps.js | 127 ++++++------- public/scripts/camps_v2.js | 30 +-- public/scripts/multiselect.js | 38 ++-- routes/admin_routes.js | 51 ++++-- routes/api_camps_routes.js | 137 ++++++++++---- routes/camps_routes.js | 50 ++--- routes/dev_routes.js | 11 +- routes/main_routes.js | 332 ++++++++++++++++++---------------- routes/main_routes.test.js | 30 +-- routes/npo_routes.js | 64 +++++-- 19 files changed, 649 insertions(+), 489 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d9a9d4ce2..7defca5ea 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -24,5 +24,8 @@ module.exports = { "no-trailing-spaces": ["off"], "key-spacing": ["off"], "block-spacing": ["off"], + "space-unary-ops": ["off"], + "comma-dangle": ["off"], + "one-var": ["off"], } }; \ No newline at end of file diff --git a/app.js b/app.js index cfb02de3a..aefabac67 100644 --- a/app.js +++ b/app.js @@ -19,13 +19,13 @@ log.info('Spark is starting...'); var app = express(); // Middleware registration -app.use(favicon(__dirname + '/public/favicon.ico')); +app.use(favicon(path.join(__dirname, '/public/favicon.ico'))); // Log every HTTP request app.use(morganLogger('dev', { stream: log.logger.stream({ level: 'info', - filter: function(message) { + filter: function (message) { if ((typeof message === "undefined") || (message === null)) return true; return ! (message.includes('/stylesheets/') || message.includes('/images/')); @@ -49,7 +49,7 @@ app.use(compileSass({ })); app.use(express.static(path.join(__dirname, 'public'))); -app.use(function(req, res, next) { +app.use(function (req, res, next) { res.locals.req = req; res.locals.path = req.path.split('/'); next(); @@ -112,8 +112,8 @@ i18next //cookieExpirationDate: new Date(), //cookieDomain: 'SparkMidburn' } - }, function() { - middleware.addRoute(i18next, '/:lng', ['en', 'he'], app, 'get', function(req, res) { + }, function () { + middleware.addRoute(i18next, '/:lng', ['en', 'he'], app, 'get', function (req, res) { //endpoint function log.info("ROUTE"); }); @@ -165,7 +165,7 @@ log.info('Spark environment: NODE_ENV =', process.env.NODE_ENV, ', app.env =', a // ============== // Catch 404 and forward to error handler -app.use(function(req, res, next) { +app.use(function (req, res, next) { var err = new Error('Not Found: ' + req.url); err.status = 404; next(err); @@ -174,9 +174,9 @@ app.use(function(req, res, next) { // Development error handler - will print stacktrace if (app.get('env') === 'development') { - app.use(function(err, req, res, next) { + app.use(function (err, req, res, next) { // Handle CSRF token errors - if (err.code == 'EBADCSRFTOKEN') { + if (err.code === 'EBADCSRFTOKEN') { res.status(403); res.render('pages/error', { errorMessage: 'Illegal action. Your connection details has been logged.', @@ -195,9 +195,9 @@ if (app.get('env') === 'development') { } // Production error handler - no stacktraces leaked to user else { - app.use(function(err, req, res, next) { + app.use(function (err, req, res, next) { // Handle CSRF token errors - if (err.code == 'EBADCSRFTOKEN') { + if (err.code === 'EBADCSRFTOKEN') { res.status(403); res.render('pages/error', { errorMessage: 'Illegal action. Your connection details has been logged.', @@ -214,11 +214,11 @@ else { } // Handler for unhandled rejections -process.on('unhandledRejection', function(reason, p) { +process.on('unhandledRejection', function (reason, p) { log.error("Possibly Unhandled Rejection at: Promise ", p, " reason: ", reason); }); -process.on('warning', function(warning) { +process.on('warning', function (warning) { log.warn(warning.name); // Print the warning name log.warn(warning.message); // Print the warning message log.warn(warning.stack); // Print the stack trace @@ -230,4 +230,4 @@ app.use(fileUpload()); // == Export our app == module.exports = app; -log.info("--- Spark is running :) ---"); +log.info("--- Spark is running :) ---"); \ No newline at end of file diff --git a/config/default.js b/config/default.js index 6c673bdfe..8d79cc81d 100644 --- a/config/default.js +++ b/config/default.js @@ -1,6 +1,6 @@ const opsworks = require('../opsworks.js'); -module.exports = { +module.exports = { database: opsworks.db, server: opsworks.server, @@ -24,4 +24,4 @@ module.exports = { }, published_camps_origin: 'http://54.194.247.12' -}; +}; \ No newline at end of file diff --git a/libs/logger.js b/libs/logger.js index a01760f00..ab2de6f62 100644 --- a/libs/logger.js +++ b/libs/logger.js @@ -1,46 +1,44 @@ const path = require('path'); const winston = require('winston'); -const config = require('config'); const assert = require('assert'); const sprintf = require("sprintf-js").sprintf; const dateFormat = require('dateformat'); - -module.exports = function(module) { +module.exports = function (module) { assert(module); assert(module.id); - + var appDir = path.dirname(require.main.filename); var id = path.relative(appDir, module.id); - - var logger = new (winston.Logger)({ - transports: [ - new (winston.transports.Console)({ - timestamp: function() { - return dateFormat(Date.now(), "dd/mm/yy hh:MM:ss.l"); - }, - formatter: function(options) { - // Return string will be passed to logger. - return sprintf("%-33s", options.timestamp() +' '+ options.level.toUpperCase() +' '+ id + ' : ') + (options.message ? options.message : '') + - (options.meta && Object.keys(options.meta).length ? '\n\t'+ JSON.stringify(options.meta) : '' ); - } - }) - ] + + var logger = new(winston.Logger)({ + transports: [ + new(winston.transports.Console)({ + timestamp: function () { + return dateFormat(Date.now(), "dd/mm/yy hh:MM:ss.l"); + }, + formatter: function (options) { + // Return string will be passed to logger. + return sprintf("%-33s", options.timestamp() + ' ' + options.level.toUpperCase() + ' ' + id + ' : ') + (options.message ? options.message : '') + + (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : ''); + } + }) + ] }); - function log (level, msg, vars) { - logger.log(level, msg, vars); + function log(level, msg, vars) { + logger.log(level, msg, vars); } // Make Morgan log work with Winston // http://stackoverflow.com/a/28824464/11236 - logger.stream = function(params) { + logger.stream = function (params) { return { - write: function(message, encoding){ + write: function (message, encoding) { if (params.filter && !params.filter(message)) { return; } - + if (message.endsWith('\n')) { message = message.slice(0, -1); } @@ -48,24 +46,24 @@ module.exports = function(module) { } } }; - + return { - log : log, - - logger : logger, - + log: log, + + logger: logger, + // Aliases - debug : function (msg, vars) { + debug: function (msg, vars) { log('debug', msg, vars); }, - info : function (msg, vars) { + info: function (msg, vars) { log('info', msg, vars); }, - warn : function (msg, vars) { + warn: function (msg, vars) { log('warn', msg, vars); }, - error : function (msg, vars) { + error: function (msg, vars) { log('error', msg, vars); }, }; -} +} \ No newline at end of file diff --git a/libs/passport.js b/libs/passport.js index be004d03e..3058ee5e3 100644 --- a/libs/passport.js +++ b/libs/passport.js @@ -13,9 +13,11 @@ var constants = require('../models/constants'); * @param password * @param done */ -var drupal_login = function(email, password, done) { - DrupalUser.forge({name: email}).fetch().then(function(drupalUser) { - if (drupalUser && drupalUser.validPassword(password) && drupalUser.attributes.status == 1) { +var drupal_login = function (email, password, done) { + DrupalUser.forge({ + name: email + }).fetch().then(function (drupalUser) { + if (drupalUser && drupalUser.validPassword(password) && drupalUser.attributes.status === 1) { // valid drupal password // drupal user status is 1 // can sign up a spark user with some defaults @@ -25,7 +27,7 @@ var drupal_login = function(email, password, done) { last_name: "", gender: constants.USER_GENDERS_DEFAULT, validated: true - }, function(newUser, error) { + }, function (newUser, error) { if (newUser) { done(newUser); } else { @@ -38,8 +40,10 @@ var drupal_login = function(email, password, done) { }); }; -var login = function(email, password, done) { - new User({email: email}).fetch().then(function (user) { +var login = function (email, password, done) { + new User({ + email: email + }).fetch().then(function (user) { if (user === null) { // no corresponding spark user is found // try to get a drupal user - once drupal user is logged-in a corresponding spark user is created @@ -48,7 +52,9 @@ var login = function(email, password, done) { } else if (!user.validPassword(password)) { done(false, i18next.t('invalid_user_password')); } else if (!user.attributes.validated) { - done(false, i18next.t('user_not_validated', {email: email})); + done(false, i18next.t('user_not_validated', { + email: email + })); } else if (!user.attributes.enabled) { done(false, i18next.t('user_disabled')); } else { @@ -57,8 +63,10 @@ var login = function(email, password, done) { }); }; -var signup = function(email, password, user, done) { - var userPromise = new User({email: email}).fetch(); +var signup = function (email, password, user, done) { + var userPromise = new User({ + email: email + }).fetch(); userPromise.then(function (model) { if (model) { done(false, i18next.t('user_exists')); @@ -97,7 +105,9 @@ module.exports = function (passport) { // used to deserialize the user passport.deserializeUser(function (id, done) { - new User({user_id: id}).fetch().then(function (user) { + new User({ + user_id: id + }).fetch().then(function (user) { done(null, user); }); }); @@ -106,32 +116,31 @@ module.exports = function (passport) { // LOCAL SIGNUP ============================================================ // ========================================================================= passport.use('local-signup', new LocalStrategy({ - // by default, local strategy uses username and password, we will override with email - usernameField: 'email', - passwordField: 'password', - passReqToCallback: true // allows us to pass back the entire request to the callback - }, - function (req, email, password, done) { - signup(email, password, req.body, function(user, error) { - if (user) { - done(null, user, null); - } else { - done(null, false, req.flash('error', error)); - } - }); - })); + // by default, local strategy uses username and password, we will override with email + usernameField: 'email', + passwordField: 'password', + passReqToCallback: true // allows us to pass back the entire request to the callback + }, + function (req, email, password, done) { + signup(email, password, req.body, function (user, error) { + if (user) { + done(null, user, null); + } else { + done(null, false, req.flash('error', error)); + } + }); + })); // ========================================================================= // LOCAL LOGIN ============================================================= // ========================================================================= - passport.use('local-login', new LocalStrategy( - { + passport.use('local-login', new LocalStrategy({ usernameField: 'email', passwordField: 'password', passReqToCallback: true }, function (req, email, password, done) { - login(email, password, function(user, error) { + login(email, password, function (user, error) { if (user) { done(null, user, null); } else { @@ -140,43 +149,47 @@ module.exports = function (passport) { }); })); - // ========== - // Facebook login - // ========== - passport.use(new FacebookStrategy({ + // ========== + // Facebook login + // ========== + passport.use(new FacebookStrategy({ clientID: facebookConfig.app_id, clientSecret: facebookConfig.app_secret, callbackURL: facebookConfig.callbackBase + "/auth/facebook/callback", enableProof: true, profileFields: ['id', 'email', 'first_name', 'last_name'] }, - function(accessToken, refreshToken, profile, cb) { - if (profile.emails == undefined) { + function (accessToken, refreshToken, profile, cb) { + if (profile.emails === undefined) { // TODO: redirect user to http://lvh.me:3000/auth/facebook/reauth console.log("User didn't agree to send us his email. "); return cb(null, false); } User.query({ - where: { facebook_id: profile.id }, - orWhere: { email: profile.emails[0].value } + where: { + facebook_id: profile.id + }, + orWhere: { + email: profile.emails[0].value + } }).fetch().then(function (model) { if (model) { // 1. Clear the user's password (the user will now only be // able to login through FacebookStrategy) // 2. Save updated token and details model.save({ - password: "", - facebook_token: accessToken, - facebook_id: profile.id, - // I'm not quite sure about this. - // If a user changes his Facebook email, should we change - // it in our system? I think we should. Not convinced though. - email: profile.emails[0].values - }) - .then(function (_model) { - return cb(null, model, null); - }); + password: "", + facebook_token: accessToken, + facebook_id: profile.id, + // I'm not quite sure about this. + // If a user changes his Facebook email, should we change + // it in our system? I think we should. Not convinced though. + email: profile.emails[0].values + }) + .then(function (_model) { + return cb(null, model, null); + }); } else { var newUser = new User({ facebook_id: profile.id, @@ -195,4 +208,4 @@ module.exports = function (passport) { }); } )); -}; +}; \ No newline at end of file diff --git a/libs/payment.js b/libs/payment.js index 3562511a5..dfc65c1b3 100644 --- a/libs/payment.js +++ b/libs/payment.js @@ -9,8 +9,7 @@ module.exports = { doPay: function (items, redirectUrl, maxPayments, exemptVat, customerFirstName, customerLastName, userId, res) { request.post( - paymentConfig.iCreditUrl, - { + paymentConfig.iCreditUrl, { json: { "GroupPrivateToken": paymentConfig.iCreditGroupPrivateToken, "Items": items, @@ -22,7 +21,7 @@ module.exports = { } }, function (error, response, body) { - if (!error && response.statusCode == 200) { + if (!error && response.statusCode === 200) { log.info("iCredit result:\n", body); new Payment({ user_id: userId, @@ -30,15 +29,13 @@ module.exports = { public_sale_token: body.PublicSaleToken, url: body.URL }).save().then(function (model) { - res.redirect(body.URL); - }); - } - else { + res.redirect(body.URL); + }); + } else { //TODO handle error. log.error("iCredit ERROR!"); } } ); } -} -; +}; \ No newline at end of file diff --git a/libs/security.js b/libs/security.js index e542056b9..59d187506 100644 --- a/libs/security.js +++ b/libs/security.js @@ -1,7 +1,7 @@ var csurf = require('csurf'); -var csrfProtection = csurf({cookie: true}); - -var User = require('../models/user').User; +var csrfProtection = csurf({ + cookie: true +}); // Route middleware to make sure a user is logged in var isLoggedIn = function (req, res, next) { @@ -9,8 +9,7 @@ var isLoggedIn = function (req, res, next) { if (req.isAuthenticated()) { // If user is authenticated in the session, carry on return next(); - } - else { + } else { // If they aren't, redirect them to the login page. 'r' holds the return URL. res.redirect('/' + req.params.lng + '/login?r=' + req.url); } @@ -21,12 +20,10 @@ var isLoggedInAdmin = function (req, res, next) { if (req.isAuthenticated()) { if (req.user.isAdmin) { return next(); - } - else { + } else { res.sendStatus(403); } - } - else { + } else { // If they aren't, redirect them to the login page. 'r' holds the return URL. res.redirect('/en/login?r=' + req.url); } diff --git a/libs/user_role.js b/libs/user_role.js index a19d480b7..102e06693 100644 --- a/libs/user_role.js +++ b/libs/user_role.js @@ -1,16 +1,20 @@ -var userRole = new (require('connect-roles'))(); +var userRole = new(require('connect-roles'))(); // pre-defined roles constants / shortcuts - to allow autocompletion and prevent unexpected errors userRole.LOGGED_IN = 'logged in'; -userRole.isLoggedIn = function() {return userRole.is(userRole.LOGGED_IN);}; +userRole.isLoggedIn = function () { + return userRole.is(userRole.LOGGED_IN); +}; userRole.ADMIN = 'admin'; -userRole.isAdmin = function() {return userRole.is(userRole.ADMIN);}; +userRole.isAdmin = function () { + return userRole.is(userRole.ADMIN); +}; // roles logic - this function determines which roles a specific request / user has -userRole.use(function(req, role) { +userRole.use(function (req, role) { if (req.isAuthenticated()) { if (req.user.isAdmin) { // admin user has all roles @@ -19,7 +23,7 @@ userRole.use(function(req, role) { // normal authenticated user (not admin) // has the logged in role // checks custom roles in user object - return (role == userRole.LOGGED_IN || req.user.hasRole(role)); + return (role === userRole.LOGGED_IN || req.user.hasRole(role)); } } else { // unauthenticated user @@ -28,4 +32,4 @@ userRole.use(function(req, role) { } }); -module.exports = userRole; +module.exports = userRole; \ No newline at end of file diff --git a/models/npo_member.js b/models/npo_member.js index 33c5aa912..b5794dd51 100644 --- a/models/npo_member.js +++ b/models/npo_member.js @@ -1,12 +1,11 @@ var bookshelf = require('../libs/db').bookshelf; -var bcrypt = require('bcrypt-nodejs'); var User = require('./user').User; var constants = require('./constants.js'); var NpoMember = bookshelf.Model.extend({ tableName: constants.NPO_MEMBERS_TABLE_NAME, idAttribute: 'user_id', - user: function() { + user: function () { return this.belongsTo(User, 'user_id'); } }); @@ -15,13 +14,12 @@ var NpoMember = bookshelf.Model.extend({ module.exports = { NpoMember: NpoMember, NPO_STATUS: { - not_member: 'not_member', - request_approved: 'request_approved', - member_paid: 'member_paid', - member_should_pay: 'member_should_pay', - banned: 'banned', - request_rejected: 'request_rejected', + not_member: 'not_member', + request_approved: 'request_approved', + member_paid: 'member_paid', + member_should_pay: 'member_should_pay', + banned: 'banned', + request_rejected: 'request_rejected', applied_for_membership: 'applied_for_membership' } -}; - +}; \ No newline at end of file diff --git a/public/scripts/camps.js b/public/scripts/camps.js index 5f2d7de70..177df375b 100644 --- a/public/scripts/camps.js +++ b/public/scripts/camps.js @@ -1,13 +1,13 @@ /** * GLOBALS */ -$(document).ajaxStart(function() { +$(document).ajaxStart(function () { $('#ajax_indicator').removeClass('done').removeClass('hide').fadeIn('fast'); }); -$(document).ajaxComplete(function() { +$(document).ajaxComplete(function () { $('#ajax_indicator').addClass('done').fadeOut('slow'); }); -$(function() { +$(function () { // tooltips $('[data-toggle="tooltip"]').tooltip() }); @@ -15,7 +15,7 @@ $(function() { /** * Scroll to top - footer button */ -$('#scroll_top').click(function() { +$('#scroll_top').click(function () { $("html, body").stop().animate({ scrollTop: 0 }, '250', 'swing'); @@ -28,12 +28,12 @@ var interval = 800, typingTimer, $input = $(".camps.camp_index input[name='camp_name_en']"); -$input.keyup(function() { +$input.keyup(function () { clearTimeout(typingTimer); typingTimer = setTimeout(doneTyping, interval); }); -$input.keydown(function() { +$input.keydown(function () { clearTimeout(typingTimer); }); @@ -45,7 +45,7 @@ function doneTyping() { btn = $('#check_camp_name'); if (val.length > 3) { var data = $.get('../camps/' + val); - data.done(function() { + data.done(function () { if (data.status === 204) { input.removeClass('error'); status.removeClass('glyphicon-remove').addClass('glyphicon-ok'); @@ -62,27 +62,25 @@ function doneTyping() { } } +function getUserTemplate(data) { + return "" +} /** * getting user list from API */ -var fetchedUsersOnce = false; - function fetchUsersOnce(elm) { if (!elm.attr('fetched')) { - $.getJSON('/users', function(data) { + $.getJSON('/users', function (data) { users = data.users; for (var i = 0; i < users.length; i++) { - elm.append(template(users[i])); + elm.append(getUserTemplate(users[i])); } }); - function template(data) { - return "" - } elm.attr('fetched', true); } } -$(function() { +$(function () { var $inputs = '#edit_camp_contact_person_id, #create_camp_contact_person_id'; if ($('.camps').is('.camp_edit') || $('.camps').is('.camp_create')) { fetchUsersOnce($($inputs)); @@ -94,34 +92,36 @@ $(function() { var fetchedCampsOnce = false, $stats_table = $('.camps.stats .table'); +function getCampsTemplate(data) { + var last_update = new Date(data.updated_at).toDateString(), + created_at = new Date(data.created_at).toDateString(), + enabled = data.enabled ? + 'Yes' : + 'No'; + return "" + data.id + "" + data.camp_name_en + "" + data.contact_person + "" + data.status + "" + last_update + "" + created_at + "" + enabled + ""; +} + function fetchCampsOnce() { if (!fetchedCampsOnce) { - var data, + var data, // eslint-disable-line no-unused-vars tbody = $stats_table.find('tbody'); tbody.html(''); - $.get('/camps', function(data) { + $.get('/camps', function (data) { camps = data.camps; for (var i = 0; i < camps.length; i++) { - tbody.append(template(camps[i])); + tbody.append(getCampsTemplate(camps[i])); } data = camps; }); - function template(data) { - var last_update = new Date(data.updated_at).toDateString(), - created_at = new Date(data.created_at).toDateString(), - enabled = data.enabled - ? 'Yes' - : 'No'; - return "" + data.id + "" + data.camp_name_en + "" + data.contact_person + "" + data.status + "" + last_update + "" + created_at + "" + enabled + ""; - } fetchedCampsOnce = true; } } -function _removeCamp(camp_id) { + +function _removeCamp(camp_id) { // eslint-disable-line no-unused-vars var agree_remove = confirm('Remove camp\n\n\nThis action will remove camp #' + camp_id + '.\n\n\n---\n Are you sure?'); if (agree_remove) { - $.get("camps/" + camp_id + "/remove", function(res) { + $.get("camps/" + camp_id + "/remove", function (res) { window.location.reload(); }); } @@ -129,7 +129,7 @@ function _removeCamp(camp_id) { $stats_table.load(fetchCampsOnce()); // Search camp -$('#camps_stats_search_camp').keyup(function(input) { +$('#camps_stats_search_camp').keyup(function (input) { $('.camps.stats table').find('tr:not(.headers)').hide(); var camp_name_en = input.target.value; $('.camps.stats table').find('td:contains("' + camp_name_en + '")').parent().show(); @@ -142,7 +142,7 @@ function innerHeightChange() { 'min-height': card_height + 'px' }); } -$(function() { +$(function () { innerHeightChange(); }); @@ -151,7 +151,7 @@ function closeCards(currentButton) { } // Camp details card transition -$('.card-switcher--card2').click(function() { +$('.card-switcher--card2').click(function () { // show card-2 ; hide card-1 $('.card-second').removeClass('card-hide'); $('.card-first').addClass('card-hide'); @@ -161,7 +161,7 @@ $('.card-switcher--card2').click(function() { $('.card-switcher--card2').addClass('Btn__default'); innerHeightChange(); }); -$('.card-switcher--card1').click(function() { +$('.card-switcher--card1').click(function () { // show card-1 ; hide card-2 $('.card-second').addClass('card-hide'); $('.card-first').removeClass('card-hide'); @@ -171,7 +171,7 @@ $('.card-switcher--card1').click(function() { $('.card-switcher--card1').addClass('Btn__default'); innerHeightChange(); }); -$('.reveal_create_camp_btn').click(function() { +$('.reveal_create_camp_btn').click(function () { if (!($('.choose_name').hasClass('card-hide'))) { $('.choose_name').toggleClass('card-hide'); return; @@ -181,7 +181,7 @@ $('.reveal_create_camp_btn').click(function() { } innerHeightChange(); }); -$('.reveal_join_camp_btn').click(function() { +$('.reveal_join_camp_btn').click(function () { if (!($('.card-second').hasClass('card-hide'))) { $('.card-second').toggleClass('card-hide'); return; @@ -191,7 +191,7 @@ $('.reveal_join_camp_btn').click(function() { } innerHeightChange(); }); -$('.reveal_manage_camp_btn').click(function() { +$('.reveal_manage_camp_btn').click(function () { if (!($('.card-third').hasClass('card-hide'))) { $('.card-third').toggleClass('card-hide'); return; @@ -201,7 +201,7 @@ $('.reveal_manage_camp_btn').click(function() { } innerHeightChange(); }); -$('.card--close').click(function() { +$('.card--close').click(function () { closeCards(); }); /** @@ -214,27 +214,27 @@ function fetchOpenCamps(elm) { $.ajax({ url: '/camps_open', type: 'GET', - success: function(data) { + success: function (data) { camps = [data.camps]; for (var i = 0; i < camps.length; i++) { $('