From ce82be637d1d707e899aeee5f315da69367fa367 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Wed, 12 Feb 2014 21:20:42 -0700 Subject: [PATCH] feat(groups): add group chat notifications --- public/js/app.js | 8 ++++++-- public/js/controllers/groupsCtrl.js | 3 +++ public/js/services/groupServices.js | 10 ++++++++-- src/controllers/groups.js | 8 ++++++++ src/models/group.js | 11 +++++++++++ src/models/user.js | 7 +++++-- src/routes/apiv2.coffee | 11 +++++++++++ 7 files changed, 52 insertions(+), 6 deletions(-) diff --git a/public/js/app.js b/public/js/app.js index 57fb7a25f3..ef55bb10d4 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -114,8 +114,12 @@ window.habitrpg = angular.module('habitrpg', .state('options.social.guilds.detail', { url: '/:gid', templateUrl: 'partials/options.social.guilds.detail.html', - controller: ['$scope', 'Groups', '$stateParams', function($scope, Groups, $stateParams){ - $scope.group = Groups.Group.get({gid:$stateParams.gid}); + controller: ['$scope', 'Groups', '$stateParams', + function($scope, Groups, $stateParams){ + Groups.Group.get({gid:$stateParams.gid}, function(group){ + $scope.group = group; + Groups.seenMessage(group._id); + }); }] }) diff --git a/public/js/controllers/groupsCtrl.js b/public/js/controllers/groupsCtrl.js index 1c5bd00958..c0ba02c5a1 100644 --- a/public/js/controllers/groupsCtrl.js +++ b/public/js/controllers/groupsCtrl.js @@ -319,6 +319,9 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.text = 'Party'; $scope.group = $rootScope.party = Groups.party(); $scope.newGroup = new Groups.Group({type:'party'}); + + Groups.seenMessage($scope.group._id); + $scope.create = function(group){ group.$save(function(newGroup){ $scope.group = newGroup; diff --git a/public/js/services/groupServices.js b/public/js/services/groupServices.js index 1f72b4a648..eb0060c24c 100644 --- a/public/js/services/groupServices.js +++ b/public/js/services/groupServices.js @@ -5,8 +5,8 @@ */ angular.module('groupServices', ['ngResource']). - factory('Groups', ['API_URL', '$resource', '$q', - function(API_URL, $resource, $q) { + factory('Groups', ['API_URL', '$resource', '$q', '$http', 'User', + function(API_URL, $resource, $q, $http, User) { var Group = $resource(API_URL + '/api/v2/groups/:gid', {gid:'@_id', messageId: '@_messageId'}, { @@ -44,6 +44,12 @@ angular.module('groupServices', ['ngResource']). return tavern; }, + // On enter, set chat message to "seen" + seenMessage: function(gid){ + $http.post('/api/v2/groups/'+gid+'/chat/seen'); + User.user.newMessages[gid] = false; + }, + Group: Group } } diff --git a/src/controllers/groups.js b/src/controllers/groups.js index cfdaa2d179..4bdde2b83a 100644 --- a/src/controllers/groups.js +++ b/src/controllers/groups.js @@ -249,6 +249,14 @@ api.deleteChatMessage = function(req, res){ }); } +api.seenMessage = function(req,res,next){ + // Skip the auth step, we want this to be fast. If !found with uuid/token, then it just doesn't save + var update = {$set:{}}; + update['$set']['newMessages.'+req.params.gid+'.value'] = false; + User.update({_id:req.headers['x-api-user'], apiToken:req.headers['x-api-key']},update).exec(); + res.send(200); +} + api.likeChatMessage = function(req, res, next) { var user = res.locals.user; var group = res.locals.group; diff --git a/src/models/group.js b/src/models/group.js index f3b3cad8e5..0ecc16221e 100644 --- a/src/models/group.js +++ b/src/models/group.js @@ -106,6 +106,17 @@ GroupSchema.methods.sendChat = function(message, user){ } group.chat.unshift(message); group.chat.splice(200); + + // Kick off chat notifications in the background. + var lastSeenUpdate = {$set:{}, $inc:{_v:1}}; + lastSeenUpdate['$set']['newMessages.'+group._id] = {name:group.name,value:true}; + if (group._id == 'habitrpg') { + // TODO For Tavern, only notify them if their name was mentioned + // var profileNames = [] // get usernames from regex of @xyz. how to handle space-delimited profile names? + // User.update({'profile.name':{$in:profileNames}},lastSeenUpdate,{multi:true}).exec(); + } else { + mongoose.model('User').update({_id:{$in:group.members, $ne: user ? user._id : ''}},lastSeenUpdate,{multi:true}).exec(); + } } var cleanQuestProgress = function(merge){ diff --git a/src/models/user.js b/src/models/user.js index 2d81658e0f..2614606e91 100644 --- a/src/models/user.js +++ b/src/models/user.js @@ -207,9 +207,11 @@ var UserSchema = new Schema({ lastCron: {type: Date, 'default': Date.now}, + // {GROUP_ID: Boolean}, represents whether they have unseen chat messages + newMessages: {type: Schema.Types.Mixed, 'default': {}}, + party: { // id // FIXME can we use a populated doc instead of fetching party separate from user? - lastMessageSeen: String, order: {type:String, 'default':'level'}, quest: { key: String, @@ -245,7 +247,8 @@ var UserSchema = new Schema({ disableClasses: {type: Boolean, 'default': false}, newTaskEdit: {type: Boolean, 'default': false}, tagsCollapsed: {type: Boolean, 'default': false}, - advancedCollapsed: {type: Boolean, 'default': false} + advancedCollapsed: {type: Boolean, 'default': false}, + toolbarCollapsed: {type:Boolean, 'default':false} }, profile: { blurb: String, diff --git a/src/routes/apiv2.coffee b/src/routes/apiv2.coffee index 513fb7e312..db5a0010f0 100644 --- a/src/routes/apiv2.coffee +++ b/src/routes/apiv2.coffee @@ -488,6 +488,17 @@ module.exports = (swagger, v2) -> middleware: [auth.auth, groups.attachGroup] action: groups.postChat + # placing before route below, so that if !=='seen' it goes to next() + "/groups/{gid}/chat/seen": + spec: + method: 'POST' + description: "Flag chat messages for a particular group as seen" + parameters: [ + path 'gid','Group id','string' + ] + middleware: [] + action: groups.seenMessage + "/groups/{gid}/chat/{messageId}": spec: method: 'DELETE'