diff --git a/frontend_tests/node_tests/unread.js b/frontend_tests/node_tests/unread.js index 22b5702ef6..def47fe68c 100644 --- a/frontend_tests/node_tests/unread.js +++ b/frontend_tests/node_tests/unread.js @@ -261,7 +261,7 @@ run_test('num_unread_for_topic', () => { var message = { type: 'stream', stream_id: stream_id, - subject: 'lunch', + subject: 'LuncH', unread: true, }; @@ -283,6 +283,26 @@ run_test('num_unread_for_topic', () => { msg_ids = unread.get_msg_ids_for_stream(stream_id); assert.deepEqual(msg_ids, _.range(1, 501)); + var topic_dict = new Dict({fold_case: true}); + + var missing_topics = unread.get_missing_topics({ + stream_id: stream_id, + topic_dict: topic_dict, + }); + + assert.deepEqual(missing_topics, [ + { pretty_name: 'LuncH', message_id: 500 }, + ]); + + topic_dict.set('lUNCh', 'whatever'); + + missing_topics = unread.get_missing_topics({ + stream_id: stream_id, + topic_dict: topic_dict, + }); + + assert.deepEqual(missing_topics, []); + for (i = 0; i < num_msgs; i += 1) { message.id = i+1; unread.mark_as_read(message.id); @@ -580,6 +600,13 @@ run_test('empty_cases', () => { msg_ids = unread.get_msg_ids_for_stream(stream_id); assert.deepEqual(msg_ids, []); assert.deepEqual(unread.get_all_msg_ids(), []); + + const missing_topics = unread.get_missing_topics({ + stream_id: stream_id, + topic_dict: 'should-never-be-referenced', + }); + assert.deepEqual(missing_topics, []); + }); run_test('errors', () => { diff --git a/static/js/unread.js b/static/js/unread.js index da47f838c3..cb11c956be 100644 --- a/static/js/unread.js +++ b/static/js/unread.js @@ -46,6 +46,10 @@ function make_id_set() { return ids.keys(); }; + self.max = function () { + return _.max(ids.keys()); + }; + self.is_empty = function () { return ids.is_empty(); }; @@ -100,6 +104,10 @@ function make_bucketer(options) { key_to_bucket.each(callback); }; + self.keys = function () { + return key_to_bucket.keys(); + }; + return self; } @@ -304,6 +312,33 @@ exports.unread_topic_counter = (function () { return res; }; + self.get_missing_topics = function (opts) { + var stream_id = opts.stream_id; + var topic_dict = opts.topic_dict; + + var per_stream_bucketer = bucketer.get_bucket(stream_id); + if (!per_stream_bucketer) { + return []; + } + + var topic_names = per_stream_bucketer.keys(); + + topic_names = _.reject(topic_names, function (topic_name) { + return topic_dict.has(topic_name); + }); + + var result = _.map(topic_names, function (topic_name) { + var msgs = per_stream_bucketer.get_bucket(topic_name); + + return { + pretty_name: topic_name, + message_id: msgs.max(), + }; + }); + + return result; + }; + self.get_stream_count = function (stream_id) { var stream_count = 0; @@ -545,6 +580,10 @@ exports.get_all_msg_ids = function () { return util.sorted_ids(ids); }; +exports.get_missing_topics = function (opts) { + return exports.unread_topic_counter.get_missing_topics(opts); +}; + exports.get_msg_ids_for_starred = function () { // This is here for API consistency sake--we never // have unread starred messages. (Some day we may ironically