Skip to content

Commit

Permalink
add optional e-mail notifications for your turn
Browse files Browse the repository at this point in the history
  • Loading branch information
btouellette committed May 29, 2014
1 parent d167ecd commit 2989cba
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 17 deletions.
70 changes: 57 additions & 13 deletions app/gameserver.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* jslint smarttabs:true */
var cookie = require('cookie');
var connect = require('connect');
var nodemailer = require('nodemailer');

// load up the gamestate model
var Tile = require('./models/tile');
Expand All @@ -15,6 +16,14 @@ var User = require('./models/user');
//TODO: make sure that all items (current game, friends, etc) are kept in sync, consider just sending user and updating every time the user changes
var userToSocket = {};

var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail",
auth: {
user: "[email protected]",
pass: process.env.EMAIL_PASSWORD
}
});

module.exports = function(server, sessionStore) {

// if the tile db is empty load in the tiles,
Expand Down Expand Up @@ -130,19 +139,47 @@ module.exports = function(server, sessionStore) {
} else {
gamestate.markModified('unusedTiles');
gamestate.populate('placedTiles.tile activeTile.tile unusedTiles players.user',
'cities.meepleOffset farms.meepleOffset roads.meepleOffset cloister imageURL username',
'cities.meepleOffset farms.meepleOffset roads.meepleOffset cloister imageURL email_notifications username local.email facebook.email google.email',
function(err, gamestate) {
if(err) { console.log('send move populate err: ' + err); }
// get distinct list of user IDs in the game
var distinctUserIDs = gamestate.players.map(function(player) { return player.user._id; }).filter(function(value, index, self) {
return self.indexOf(value) === index;
});
// if players are active send them the new gamestate
for(var i = 0; i < distinctUserIDs.length; i++) {
var socketArray = userToSocket[distinctUserIDs[i]];
if(socketArray) {
for(var k = 0; k < socketArray.length; k++) {
socketArray[k].emit('sending gamestate', gamestate, false);
if(err) {
console.log('send move populate err: ' + err);
} else {
var activeUser, previousUser;
for(var j = 0; j < gamestate.players.length; j++) {
if(gamestate.players[j].active) {
activeUser = gamestate.players[j].user;
previousUser = gamestate.players[(j - 1 + gamestate.players.length) % gamestate.players.length].user;
break;
}
}
// send e-mail notification to user if they have opted in and the user has changed
if(activeUser.email_notifications && activeUser.username !== previousUser.username) {
var activeEmail = activeUser.local.email || activeUser.google.email || activeUser.facebook.email;
// send notification if we have a valid e-mail and the user doesn't have an active socket
if(activeEmail && !userToSocket[activeUser._id]) {
smtpTransport.sendMail({
from: "Concarneau <[email protected]",
to: activeEmail,
subject: "Your turn!",
text: "There is a Concarneau game where it is your turn: https://concarneau.herokuapp.com"
}, function(err, res) {
if(err) {
console.log('e-mail failed: ' + err);
}
});
}
}
// get distinct list of user IDs in the game
var distinctUserIDs = gamestate.players.map(function(player) { return player.user._id; }).filter(function(value, index, self) {
return self.indexOf(value) === index;
});
// if players are active send them the new gamestate
for(var i = 0; i < distinctUserIDs.length; i++) {
var socketArray = userToSocket[distinctUserIDs[i]];
if(socketArray) {
for(var k = 0; k < socketArray.length; k++) {
socketArray[k].emit('sending gamestate', gamestate, false);
}
}
}
}
Expand All @@ -159,7 +196,7 @@ module.exports = function(server, sessionStore) {
var friendID = user._id;
if(currentUser.friends.indexOf(user._id) === -1) {
User.findByIdAndUpdate(currentUser._id, { $addToSet: { friends: user._id }}, function(err, user) {
if(!err) {
if(!err && user) {
socket.emit('friend added', username, friendID);
currentUser = user;
}
Expand Down Expand Up @@ -200,6 +237,13 @@ module.exports = function(server, sessionStore) {
}
});
});
socket.on('email notification', function(enabled) {
User.findByIdAndUpdate(currentUser._id, { $set: { email_notifications: enabled }} , function(err, user) {
if(!err && user) {
currentUser = user;
}
});
});
});
});
});
Expand Down
3 changes: 2 additions & 1 deletion app/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ var userSchema = mongoose.Schema({
},
activeGames: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Gamestate' }], // external reference to gamestate objects
friends: [mongoose.Schema.Types.ObjectId],
username: { type: String, lowercase: true, trim: true, unique: true, sparse: true }
username: { type: String, lowercase: true, trim: true, unique: true, sparse: true },
email_notifications: Boolean

});

Expand Down
1 change: 1 addition & 0 deletions config/c9.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var argv = require('yargs').argv;
process.env.FACEBOOK_SECRET = argv.FACEBOOK_SECRET;
process.env.TWITTER_SECRET = argv.TWITTER_SECRET;
process.env.GOOGLE_SECRET = argv.GOOGLE_SECRET;
process.env.EMAIL_PASSWORD = argv.EMAIL_PASSWORD;

process.env.FACEBOOK_CALLBACK = 'https://concarneau-c9-btouellette.c9.io/auth/facebook/callback';
process.env.TWITTER_CALLBACK = 'https://concarneau-c9-btouellette.c9.io/auth/twitter/callback';
Expand Down
2 changes: 1 addition & 1 deletion config/passport.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module.exports = function(passport) {

// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, 'username friends activeGames local facebook google twitter', function(err, user) {
User.findById(id, 'username friends activeGames local facebook google twitter email_notifications', function(err, user) {
user.populate('activeGames friends', 'players.user players.active started finished username unusedTiles', function(err, user) {
user.populate({ path: 'activeGames.players.user', model: 'User', select: 'username'}, function(err, user) {
done(err, user);
Expand Down
10 changes: 10 additions & 0 deletions content/css/game.css
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,16 @@ html, body
padding-top: 3px;
}

#settings-menu .checkbox
{
margin-left: 10px;
}

#settings-menu label
{
vertical-align: -2px;
}

#svg-wrapper
{
background-color: green;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"moniker": "~0.1.2",
"connect-mongo": "~0.4.0",
"nodetime": "~0.8.15",
"newrelic": "~1.5.2"
"newrelic": "~1.5.2",
"nodemailer": "~0.6.5"
}
}
9 changes: 9 additions & 0 deletions views/game.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@
<div id="settings-menu">
<span class="menu-header">SETTINGS</span>
<a href="/profile">Profile</a>
<div class="checkbox">
<label>
<input type="checkbox"
onclick="socket.emit('email notification', this.checked)"
<%- user.email_notifications ? 'checked="true"' : '' %>
<%- !(user.facebook.email || user.google.email || user.local.email) ? 'disabled' : '' %>> E-mail notifications
</label>
<%- !(user.facebook.email || user.google.email || user.local.email) ? '(requires non-Twitter login linked in Profile)' : '' %>
</div>
<a href="/logout">Logout</a>
</div>
</div>
Expand Down
1 change: 0 additions & 1 deletion views/profile.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
<p>
<strong>id</strong>: <%= user._id %><br>
<strong>email</strong>: <%= user.local.email %><br>
<strong>password</strong>: <%= user.local.password %>
</p>
<a href="/unlink/local" class="btn btn-default">Unlink</a>
Expand Down

0 comments on commit 2989cba

Please sign in to comment.