From c1d7b06ded71a6ddf8fb4ca7bbae5211db99cca7 Mon Sep 17 00:00:00 2001
From: Julian Lam <julian@nodebb.org>
Date: Fri, 18 Aug 2017 16:30:04 -0400
Subject: [PATCH] Fixes #5873

- Notifications.getMultiple now takes an optional uid parameter
- If a notification link in dropdown points to a topic and you're
  in said topic, you will be scrolled to the post instead of
  ajaxified to it.
---
 public/src/modules/notifications.js | 15 +++++++++--
 src/notifications.js                | 39 ++++++++++++++++++++++++-----
 src/user/notifications.js           |  2 +-
 3 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/public/src/modules/notifications.js b/public/src/modules/notifications.js
index 928884b69a..ea78918c1b 100644
--- a/public/src/modules/notifications.js
+++ b/public/src/modules/notifications.js
@@ -1,7 +1,7 @@
 'use strict';
 
 
-define('notifications', ['sounds', 'translator', 'components'], function (sounds, translator, components) {
+define('notifications', ['sounds', 'translator', 'components', 'navigator'], function (sounds, translator, components, navigator) {
 	var Notifications = {};
 
 	var unreadNotifs = {};
@@ -20,7 +20,18 @@ define('notifications', ['sounds', 'translator', 'components'], function (sounds
 			Notifications.loadNotifications(notifList);
 		});
 
-		notifList.on('click', '[data-nid]', function () {
+		notifList.on('click', '[data-nid]', function (e) {
+			// Scroll to index if already in topic (gh#5873)
+			var index = $(this).attr('data-index');
+			var tid = $(this).attr('data-tid');
+			if (index && ajaxify.data.template.topic && parseInt(ajaxify.data.tid, 10) === parseInt(tid, 10)) {
+				e.stopPropagation();
+				e.preventDefault();
+
+				navigator.scrollToIndex(index, true);
+				notifTrigger.dropdown('toggle');
+			}
+
 			var unread = $(this).hasClass('unread');
 			if (!unread) {
 				return;
diff --git a/src/notifications.js b/src/notifications.js
index 58ccf2e8fa..715f4cf264 100644
--- a/src/notifications.js
+++ b/src/notifications.js
@@ -13,6 +13,7 @@ var groups = require('./groups');
 var meta = require('./meta');
 var batch = require('./batch');
 var plugins = require('./plugins');
+var posts = require('./posts');
 var utils = require('./utils');
 
 var Notifications = module.exports;
@@ -22,13 +23,19 @@ Notifications.startJobs = function () {
 	new cron('*/30 * * * *', Notifications.prune, null, true);
 };
 
-Notifications.get = function (nid, callback) {
-	Notifications.getMultiple([nid], function (err, notifications) {
+Notifications.get = function (nid, uid, callback) {
+	Notifications.getMultiple([nid], uid, function (err, notifications) {
 		callback(err, Array.isArray(notifications) && notifications.length ? notifications[0] : null);
 	});
 };
 
-Notifications.getMultiple = function (nids, callback) {
+Notifications.getMultiple = function (nids, uid, callback) {
+	if (typeof uid === 'function' && !callback) {
+		// no uid passed in
+		callback = uid;
+		uid = undefined;
+	}
+
 	if (!Array.isArray(nids) || !nids.length) {
 		return setImmediate(callback, null, []);
 	}
@@ -37,8 +44,19 @@ Notifications.getMultiple = function (nids, callback) {
 	});
 
 	var notifications;
+	var userSettings;
 
 	async.waterfall([
+		function (next) {
+			if (!uid) {
+				return setImmediate(next);
+			}
+
+			User.getSettings(uid, function (err, settings) {
+				userSettings = settings;
+				next(err);
+			});
+		},
 		function (next) {
 			db.getObjects(keys, next);
 		},
@@ -51,7 +69,7 @@ Notifications.getMultiple = function (nids, callback) {
 			User.getUsersFields(userKeys, ['username', 'userslug', 'picture'], next);
 		},
 		function (usersData, next) {
-			notifications.forEach(function (notification, index) {
+			async.eachOf(notifications, function (notification, index, next) {
 				if (notification) {
 					notification.datetimeISO = utils.toISOString(notification.datetime);
 
@@ -68,10 +86,19 @@ Notifications.getMultiple = function (nids, callback) {
 					} else if (notification.image === 'brand:logo' || !notification.image) {
 						notification.image = meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png';
 					}
+
+					if (notification.path.startsWith('/post/')) {
+						posts.getPidIndex(notification.pid, notification.tid, userSettings.topicPostSort, function (err, index) {
+							notification.index = index;
+							next(err);
+						});
+					} else {
+						next();
+					}
 				}
+			}, function (err) {
+				next(err, notifications);
 			});
-
-			next(null, notifications);
 		},
 	], callback);
 };
diff --git a/src/user/notifications.js b/src/user/notifications.js
index 4e2dcba7e8..cb3f208e0f 100644
--- a/src/user/notifications.js
+++ b/src/user/notifications.js
@@ -140,7 +140,7 @@ UserNotifications.getNotifications = function (nids, uid, callback) {
 		function (next) {
 			async.parallel({
 				notifications: function (next) {
-					notifications.getMultiple(nids, next);
+					notifications.getMultiple(nids, uid, next);
 				},
 				hasRead: function (next) {
 					db.isSortedSetMembers('uid:' + uid + ':notifications:read', nids, next);