From ac1d4a3a179669b857360a647bec5d8f8849e1c6 Mon Sep 17 00:00:00 2001 From: Emmanuel Prochasson Date: Fri, 12 Jul 2013 16:43:10 +0800 Subject: [PATCH] Moved user presence to an extra collection. Fix Invisible mode. Show conversation --- TODO | 9 +-- client/helpers/presence.js | 11 +--- client/lexicon/lexicon.js | 4 ++ client/main.js | 49 ++++++++-------- client/views/mailbox/conversation.html | 19 +++++-- client/views/mailbox/conversation.js | 28 ++++++++- client/views/widgets/online_friends.js | 13 +++-- lib/collections/presences.js | 9 +++ main.config.js | 18 +++--- server/presence.js | 26 +++++++-- server/publications.js | 79 ++++++++++++++++---------- 11 files changed, 168 insertions(+), 97 deletions(-) create mode 100644 lib/collections/presences.js diff --git a/TODO b/TODO index 448706f..f597982 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,7 @@ Make sure logout users are redirected to the front page, always. - Browse users Setting page - Activities: what did one do, what can of activity can the others see. - Check user security: do not allow user to change all their profile. - - -myFriends and myOnlineFriends are redundant. Add pagination to myFriends, for the page that lists all friends. - +myFriends and myOnlineFriends are redundant. +Move images to S3. \ No newline at end of file diff --git a/client/helpers/presence.js b/client/helpers/presence.js index fa1a652..de433d0 100644 --- a/client/helpers/presence.js +++ b/client/helpers/presence.js @@ -5,7 +5,7 @@ Meteor.startup(function(){ // update presences every interval presenceTick = Meteor.setInterval(function() { Meteor.Presence.update(); - }, Presence.checkInterval || 1000); + }, Presences.checkInterval || 1000); }); Meteor.Presence = { @@ -18,14 +18,7 @@ Meteor.Presence = { Meteor.autorun(function(){ Session.get('last-presence-at'); // Just to hit the context. - var settings = Session.get('settings')||{}; - var invisible = settings.invisible; - if(invisible == undefined){ - // Default to true, to avoid "blinking" on other clients - // (otherwise, invisible users get set online for a short time, before being updated to invisible) - invisible = true; - } - Meteor.call('setUserPresence', invisible, function(err,res){ + Meteor.call('setUserPresence', function(err,res){ if(err){ console.log('setUserPresence: huho'); } diff --git a/client/lexicon/lexicon.js b/client/lexicon/lexicon.js index 0dd65f4..5524f4c 100644 --- a/client/lexicon/lexicon.js +++ b/client/lexicon/lexicon.js @@ -37,3 +37,7 @@ Meteor.i18nMessages.question = { dob: 'Date of Birth', dob_help: 'Select your date of birth' }; + +Meteor.i18nMessages.messages = { + you: 'you' +}; diff --git a/client/main.js b/client/main.js index c50c3b6..94aa8c3 100644 --- a/client/main.js +++ b/client/main.js @@ -1,32 +1,33 @@ -// All my data -Meteor.subscribe('myData', function(){ - Session.set('settings', Meteor.user().settings||{}); -}); -// My own picture. -Meteor.subscribe('myPictures'); +Meteor.startup(function(){ + // All my data + Meteor.subscribe('myData', function(){ + Session.set('settings', Meteor.user().settings||{}); + }); + // My own picture. + Meteor.subscribe('myPictures'); -// Online friends widget. -Meteor.subscribe('myOnlineFriends'); + // Online friends widget. + Meteor.subscribe('myOnlineFriends'); -// The list of my friends. -Meteor.subscribe('myFriendList'); + // The list of my friends. + Meteor.subscribe('myFriendList'); -// My conversations -conversationsHandle = Meteor.subscribeWithPagination('myConversations', 3); + // My conversations + conversationsHandle = Meteor.subscribeWithPagination('myConversations', 3); -var currentConversation = function(){ - return Session.get('currentConversation') || null; -}; + oneConversationHandle = Meteor.subscribeWithPagination('oneConversation', function(){ + return Session.get('currentConversation') || null; + }, Messages.messagePerPage); -oneConversationHandle = Meteor.subscribeWithPagination('oneConversation', currentConversation, 4); + // When visiting someone's profile + Deps.autorun(function () { + userProfileHandle = Meteor.subscribe("oneUserProfile", Session.get("currentUserProfile")); + userPictureHandle = Meteor.subscribe("oneUserPictures", Session.get("currentUserProfile")); + }); -// When visiting someone's profile -Deps.autorun(function () { - userProfileHandle = Meteor.subscribe("oneUserProfile", Session.get("currentUserProfile")); - userPictureHandle = Meteor.subscribe("oneUserPictures", Session.get("currentUserProfile")); -}); + // Questions for the profile form. + Meteor.subscribe('questions'); -// Questions for the profile form. -Meteor.subscribe('questions'); + Meteor.subscribe('adminShowEveryone'); -Meteor.subscribe('showFuckingEveryone'); +}); \ No newline at end of file diff --git a/client/views/mailbox/conversation.html b/client/views/mailbox/conversation.html index fd89ff6..42274bb 100644 --- a/client/views/mailbox/conversation.html +++ b/client/views/mailbox/conversation.html @@ -1,9 +1,16 @@ + + \ No newline at end of file diff --git a/client/views/mailbox/conversation.js b/client/views/mailbox/conversation.js index cd92467..07a803f 100644 --- a/client/views/mailbox/conversation.js +++ b/client/views/mailbox/conversation.js @@ -1,7 +1,31 @@ Template.conversation.helpers({ messages: function(){ - console.log('message'); +// + var conversation = Conversations.findOne(Session.get('currentConversation')); + if(!conversation){ + return; + } - return Messages.find({}, {sort: {timestamp: -1}}); + return Messages.find( + { + $or: [ + {from: Meteor.userId(), to: conversation.with}, + {to: Meteor.userId(), from: conversation.with} + ] + }, + {sort: {sent: -1}} + ); + } +}); +Template.message.helpers({ + timestamp: function(){ + return moment(this.sent).fromNow(); + }, + sender: function(){ + console.log(this); + return this.from == Meteor.userId()? __('messages.you') : Meteor.users.findOne(this.from)['profile'].name; + }, + receiver: function(){ + return this.to == Meteor.userId()? __('messages.you') : Meteor.users.findOne(this.to)['profile'].name; } }); \ No newline at end of file diff --git a/client/views/widgets/online_friends.js b/client/views/widgets/online_friends.js index 68ec040..1a6dcb5 100644 --- a/client/views/widgets/online_friends.js +++ b/client/views/widgets/online_friends.js @@ -1,10 +1,15 @@ Template.online_friends.helpers({ friends: function(){ - var friends = Meteor.user().friends || []; - return Meteor.users.find({'profile.online': 1, _id: {$in: friends}}); + var friends = Presences.find({}); + var ids = []; + friends.forEach(function(f){ + ids.push(f.user); + }); + + return Meteor.users.find({_id: {$in: ids}}, {sort:{'profile.name': 1}}); }, count: function(){ - var friends = Meteor.user().friends || []; - return Meteor.users.find({'profile.online': 1, _id: {$in: friends}}).count(); + // Presence subscription only show online users... + return Presences.find({}).count() + 1; } }); \ No newline at end of file diff --git a/lib/collections/presences.js b/lib/collections/presences.js new file mode 100644 index 0000000..2ccf586 --- /dev/null +++ b/lib/collections/presences.js @@ -0,0 +1,9 @@ +Presences = new Meteor.Collection('presences'); + + +// Can't touch me +Presences.deny({ + insert: function(){ return true; }, + update: function(){ return true; }, + remove: function(){ return true; } +}); \ No newline at end of file diff --git a/main.config.js b/main.config.js index 70787a5..e99ffa9 100644 --- a/main.config.js +++ b/main.config.js @@ -10,8 +10,9 @@ if(Meteor.isClient){ filePickerKey = "Av2HCAqJSM2aHdX5yKTZtz"; } + /* - Users + Users configuration */ // What fields are public for everyone Meteor.user.publicProfileInformation = { @@ -29,15 +30,13 @@ Meteor.user.privateProfileInformation = { // What field I can see about myself Meteor.user.myProfileInformation = { - // show more information 'profile': 1, 'friends': 1, 'settings': 1 }; - /* - Messages + Messages configuration */ // Duration to measure velocity (default 2 minutes). Messages.velocityCaliber = 30*1000; @@ -47,9 +46,11 @@ Messages.onlineMaxVelocity = 15; Messages.offlineMaxVelocity = 5; // Cooldown penalty (def: 1 minute) Messages.cooldownPenalty = 10*1000; +// How many messages to display per page. +Messages.messagePerPage = 2; /* - User posted Pictures. + User posted Pictures configuration */ // Fields people can change Pictures.authorizedFields = ['main']; @@ -59,10 +60,9 @@ Pictures.maxFileSize = 1024*1024; Pictures.maxFilePerUser = -1; /* - Check user presence + Check user presence configuration */ -Presence = {}; // How often do we update presence (ms) -Presence.checkInterval = 2000; +Presences.checkInterval = 2000; // How long before a user is considered out (ms). -Presence.TimeOut = 10000; +Presences.TimeOut = 10000; diff --git a/server/presence.js b/server/presence.js index 65292ac..fd874a6 100644 --- a/server/presence.js +++ b/server/presence.js @@ -2,15 +2,29 @@ //Check user presence Meteor.methods({ - setUserPresence: function(invisible){ - // We record user presence regardless of their online status. - return Meteor.users.update(Meteor.userId(), {$set: {lastseen: new Date().getTime(), 'profile.online': 0+!invisible, 'settings.invisible': invisible}}); + setUserPresence: function(){ + if(!Presences.findOne({user: Meteor.userId()})){ + return Presences.insert({ + user: Meteor.userId(), + lastseen: new Date().getTime(), + online: 1 + }) + } else { + return Presences.update( + {user: Meteor.userId()}, + {$set: {lastseen: new Date().getTime(), 'online': 1}} + ); + } + }, + setInvisible: function(invisible){ + return Presences.update({user: this.userId}, {$set: {invisible: Boolean(invisible)}}) && + Meteor.users.findOne(this.userId, {$set: {'settings.invisible': Boolean(invisible)}}); } }); Meteor.startup(function(){ -// Update user not connected. + // Update user not connected. Meteor.setInterval(function(){ - Meteor.users.update({lastseen: {$lt:(new Date().getTime() - Presence.TimeOut)}}, {$set: {'profile.online': 0}}); - }, Presence.checkInterval || 1000); + Presences.update({lastseen: {$lt:(new Date().getTime() - Presences.TimeOut)}}, {$set: {'online': 0}}); + }, Presences.checkInterval || 1000); }); diff --git a/server/publications.js b/server/publications.js index b55a839..e0e2356 100644 --- a/server/publications.js +++ b/server/publications.js @@ -1,4 +1,3 @@ - Meteor.publish("myData", function () { return Meteor.users.find( {_id: this.userId}, @@ -6,7 +5,6 @@ Meteor.publish("myData", function () { ); }); - Meteor.publish('questions', function(){ return Questions.find(); }); @@ -16,7 +14,7 @@ Meteor.publish("myConversations", function(limit) { handle: this, collection: Conversations, filter: {owner: this.userId}, - options: {limit: limit}, + options: {limit: limit, sort: {timestamp: -1}}, mappings: [{ // Publish people sending message as well, as they might not be in your friendlist. key: 'with', collection: Meteor.users, @@ -26,22 +24,32 @@ Meteor.publish("myConversations", function(limit) { }); Meteor.publish("oneConversation", function(conversation, limit){ - if(!conversation){ return []; } - var conv = Conversations.findOne(conversation); - console.log(conv); - return Messages.find({ - $or: [{from: conv.owner, to: conv.with},{from: conv.with, to: conv.owner}] - }); -}); + if(!(conv.owner == this.userId)){ + return []; + } -Meteor.publish("myMessages", function(limit, skip){ - return Messages.find({ $or: { to: this.userId, from: this.userId}}, {limit: limit, skip: skip}); -}); + var query = { + $or: [{from: this.userId, to: conv.with},{from: conv.with, to: this.userId}] + }; + Meteor.publishWithRelations({ + handle: this, + collection: Messages, + filter: query, + options: {limit: limit, sort: {sent: -1}}, + mappings: [{ // Publish people sending message as well, as they might not be in your friendlist. + key: 'from', + collection: Meteor.users, + options: {fields: Meteor.user.publicProfileInformation} + }] + }); + + return Messages.find(query, {limit: limit, sort: {sent: -1}}); +}); Meteor.publish("myFriendList", function(){ // load a very light version of the friendlist @@ -55,26 +63,21 @@ Meteor.publish("myFriendList", function(){ ); }); -// Remove! -Meteor.publish("showFuckingEveryone", function(){ - var user = Meteor.users.findOne(this.userId); - if(user.isAdmin){ - return Meteor.users.find({}); - } else { - return []; - } -}); // Also maintains user online/offline status Meteor.publish("myOnlineFriends", function(){ var friends = Meteor.users.findOne(this.userId).friends || []; - return Meteor.users.find( - { 'profile.online': 1, 'visible': 1, 'settings.invisible': false, _id: {$in: friends}}, - { - sort: {lastConnected : -1}, - fields: Meteor.user.privateProfileInformation - } - ); + Meteor.publishWithRelations({ + handle: this, + collection: Presences, + filter: {user: {$in : friends}, online: 1, invisible: false}, + options: {fields: {user: 1}, sort:{ lastseen: -1}}, + mappings: [{ // Publish people sending message as well, as they might not be in your friendlist. + key: 'user', + collection: Meteor.users, + options: {fields: Meteor.user.publicProfileInformation} + }] + }); }); @@ -119,4 +122,20 @@ Meteor.publish('oneUserPictures', function(userId){ Meteor.publish('myPictures', function(){ return Pictures.find({owner: this.userId}); -}); \ No newline at end of file +}); + + +/* + Admin ! + */ + +// Remove! +Meteor.publish("adminShowEveryone", function(){ + var user = Meteor.users.findOne(this.userId); + if(user.isAdmin){ + return Meteor.users.find({}); + } else { + return []; + } +}); +