From e7408ba6f1ee61e0e6ace27d99d09d2a27fff532 Mon Sep 17 00:00:00 2001 From: Yaydoc Bot Date: Wed, 2 Aug 2017 23:40:33 +0530 Subject: [PATCH] Fixes #342: adding support for sending notification if access token revoked --- app.js | 10 +++++++++- backend/github.js | 21 +++++++++++++++++++++ backend/mailer.js | 21 +++++++++++++++++++++ backend/queue.js | 27 +++++++++++++++++++++++++++ backend/task.js | 34 ++++++++++++++++++++++++++++++++++ model/user.js | 36 +++++++++++++++++++++++++++++++++++- package.json | 1 + util/passport.js | 4 +--- 8 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 backend/queue.js create mode 100644 backend/task.js diff --git a/app.js b/app.js index d7df7ecf..ddd59ec0 100644 --- a/app.js +++ b/app.js @@ -8,7 +8,8 @@ var passport = require("passport"); var dotenv = require("dotenv"); var session = require("express-session"); var mongoose = require("mongoose"); - +var task = require("./backend/task"); +var cron = require('node-cron'); dotenv.config({path: './.env'}); require('./util/passport')(passport); @@ -96,6 +97,13 @@ io.on('connection', function(socket){ }) }); + +// Tasks runs on every 24 hrs + +cron.schedule('* 23 * * *', function(){ + task.checkExpiredToken(); +}); + // catch 404 and forward to error handler app.use(function(req, res, next) { res.status(404); diff --git a/backend/github.js b/backend/github.js index 32512449..059c9f30 100644 --- a/backend/github.js +++ b/backend/github.js @@ -263,3 +263,24 @@ exports.getRepositoryBranches = function (name, callback) { } }); }; +/** + * Get user details by access token + * @param accessToken: Access Token of the user + * @param callback: callback + */ + +exports.retriveUser = function (accessToken, callback) { + request({ + url: 'https://api.github.com/users/', + headers: { + 'User-Agent': 'Yaydoc', + 'Authorization': 'token ' + crypter.decrypt(accessToken) + } + }, function (error, response, body) { + if (response.status !== 200) { + callback({statusCode: response.status}, null); + } else { + callback(error, JSON.parse(body)); + } + }) +}; diff --git a/backend/mailer.js b/backend/mailer.js index 45dda35d..ba1f9a66 100644 --- a/backend/mailer.js +++ b/backend/mailer.js @@ -74,3 +74,24 @@ exports.sendMailOnBuild = function (buildStatus, email, repository) { } }); }; + +exports.sendMailOnTokenFailure = function (email) { + var client = nodemailer.createTransport(sgTransport(options)); + + var textContent = 'Access token for Yaydoc is expired. Sign in once again to continue the service'; + var htmlContent = 'Access token for Yaydoc is expired. Sign in once again to continue the service'; + + client.sendMail({ + from: 'info@yaydoc.com', + to: email, + subject: 'Token expired - Yaydoc', + text: textContent, + html: htmlContent + }, function (error, info) { + if (error) { + console.log(error); + } else { + console.log('Message sent: ' + info.response); + } + }); +}; diff --git a/backend/queue.js b/backend/queue.js new file mode 100644 index 00000000..c0a7e817 --- /dev/null +++ b/backend/queue.js @@ -0,0 +1,27 @@ +const github = require("./github.js"); +const mailer = require("./mailer"); +const async = require("async"); +User = require("../model/user"); +var tokenRevokedQueue = async.queue(function (user, done) { + github.retriveUser(user.token, function (error, userData) { + if (error) { + if (user.expired === false) { + mailer.sendMailOnTokenFailure(user.email); + User.updateUserById(user.id, { + expired: true + }, function(error, data) { + if (error) { + console.log(error); + } + }); + } + done(); + } else { + done(); + } + }) +}, 2); + +exports.addTokenRevokedJob = function(user) { + tokenRevokedQueue.push(user); +}; diff --git a/backend/task.js b/backend/task.js new file mode 100644 index 00000000..d156c7c2 --- /dev/null +++ b/backend/task.js @@ -0,0 +1,34 @@ +const github = require("./github") +const queue = require("./queue") + +User = require("../model/user"); + +exports.checkExpiredToken = function () { + User.count(function (error, count) { + if (error) { + console.log(error); + } else { + var page = 0; + if (count < 10) { + page = 1; + } else { + page = count / 10; + if (page * 10 < count) { + page = (count + 10) /10; + } + } + for (var i = 0; i <= page; i++) { + User.paginateUsers(i, 10, + function (error, users) { + if (error) { + console.log(error); + } else { + users.forEach(function(user) { + queue.addTokenRevokedJob(user); + }) + } + }) + } + } + }) +} diff --git a/model/user.js b/model/user.js index 3bd78f9b..91d6a101 100644 --- a/model/user.js +++ b/model/user.js @@ -5,7 +5,8 @@ const userSchema = mongoose.Schema({ token: String, email: String, name: String, - username: String + username: String, + expired: Boolean }); const User = module.exports = mongoose.model('User', userSchema); @@ -27,3 +28,36 @@ module.exports.getUserById = function(id, callback) { module.exports.getUserByUsername = function(username, callback) { User.findOne({username: username}, callback); }; + +/** + * Count the number of repository + */ + +module.exports.countUsers = function (callback) { + User.count({}, callback); +}; + +/** + * paginates repositories + * @param page: n'th page + * @param limit: limit for number of repository to return + */ + +module.exports.paginateUsers = function (page, limit, callback) { + var skip = 0; + if (page > 1) { + skip = page * limit; + } + User.find({}).skip(skip).limit(limit).exec(callback); +}; + +/** + * Update the user by Github's Users id + * @param id: Github's user id + * @param update: user update + */ +module.exports.updateUserById = function(id, update, callback) { + User.update({id: id}, update, function(error, data) { + callback(error, data); + }); +}; diff --git a/package.json b/package.json index e3f6e377..afe39050 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "moment": "^2.18.1", "mongoose": "^4.11.0", "morgan": "~1.8.1", + "node-cron": "^1.2.0", "nodemailer": "^4.0.1", "passport": "^0.3.2", "passport-github": "^1.1.0", diff --git a/util/passport.js b/util/passport.js index 0f484c0e..15d76d97 100644 --- a/util/passport.js +++ b/util/passport.js @@ -26,8 +26,7 @@ module.exports = function (passport) { return done(error); } if (user) { - user.token = crypter.encrypt(accessToken); - user.save(); + return done(null, user); } else { let newUser = new User(); @@ -57,5 +56,4 @@ module.exports = function (passport) { cb(null, profile); } )); - };