2018-04-19 15:46:56 +02:00
|
|
|
var buddy_data = (function () {
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
This is the main model code for building the buddy list.
|
|
|
|
We also rely on presence.js to compute the actual presence
|
|
|
|
for users. We glue in other "people" data and do
|
|
|
|
filtering/sorting of the data that we'll send into the view.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2018-04-23 23:13:52 +02:00
|
|
|
exports.max_size_before_shrinking = 600;
|
2018-04-20 18:22:28 +02:00
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
var presence_descriptions = {
|
2019-02-14 10:14:35 +01:00
|
|
|
away_me: 'is unavailable',
|
|
|
|
away_them: 'is unavailable',
|
2018-04-19 15:46:56 +02:00
|
|
|
active: 'is active',
|
2018-12-18 19:34:45 +01:00
|
|
|
idle: 'is not active',
|
2018-04-19 15:46:56 +02:00
|
|
|
};
|
|
|
|
|
2018-04-22 17:46:20 +02:00
|
|
|
var fade_config = {
|
|
|
|
get_user_id: function (item) {
|
|
|
|
return item.user_id;
|
|
|
|
},
|
|
|
|
fade: function (item) {
|
|
|
|
item.faded = true;
|
|
|
|
},
|
|
|
|
unfade: function (item) {
|
|
|
|
item.faded = false;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2019-02-17 02:10:42 +01:00
|
|
|
exports.get_user_circle_class = function (user_id) {
|
|
|
|
var status = exports.buddy_status(user_id);
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case 'active':
|
|
|
|
return 'user_circle_green';
|
|
|
|
case 'idle':
|
|
|
|
return 'user_circle_orange';
|
|
|
|
case 'away_them':
|
|
|
|
case 'away_me':
|
2019-03-01 17:31:59 +01:00
|
|
|
return 'user_circle_empty_line';
|
2019-02-17 02:10:42 +01:00
|
|
|
default:
|
|
|
|
return 'user_circle_empty';
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-12-20 15:55:20 +01:00
|
|
|
exports.level = function (user_id) {
|
2018-12-18 18:50:58 +01:00
|
|
|
if (people.is_my_user_id(user_id)) {
|
|
|
|
// Always put current user at the top.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-12-19 21:16:03 +01:00
|
|
|
var status = exports.buddy_status(user_id);
|
2018-09-08 15:54:52 +02:00
|
|
|
|
2018-04-20 18:22:28 +02:00
|
|
|
switch (status) {
|
2018-05-07 01:38:14 +02:00
|
|
|
case 'active':
|
|
|
|
return 1;
|
|
|
|
case 'idle':
|
|
|
|
return 2;
|
2018-12-19 21:16:03 +01:00
|
|
|
case 'away_them':
|
|
|
|
return 3;
|
2018-05-07 01:38:14 +02:00
|
|
|
default:
|
|
|
|
return 3;
|
2018-04-19 15:46:56 +02:00
|
|
|
}
|
2018-12-20 15:55:20 +01:00
|
|
|
};
|
2018-04-19 15:46:56 +02:00
|
|
|
|
2018-12-19 21:16:03 +01:00
|
|
|
exports.buddy_status = function (user_id) {
|
|
|
|
if (user_status.is_away(user_id)) {
|
|
|
|
if (people.is_my_user_id(user_id)) {
|
|
|
|
return 'away_me';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'away_them';
|
|
|
|
}
|
|
|
|
|
|
|
|
// get active/idle/etc.
|
|
|
|
return presence.get_status(user_id);
|
|
|
|
};
|
|
|
|
|
2018-04-20 18:22:28 +02:00
|
|
|
exports.compare_function = function (a, b) {
|
2018-12-20 15:55:20 +01:00
|
|
|
var level_a = exports.level(a);
|
|
|
|
var level_b = exports.level(b);
|
2018-04-19 15:46:56 +02:00
|
|
|
var diff = level_a - level_b;
|
|
|
|
if (diff !== 0) {
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort equivalent PM names alphabetically
|
|
|
|
var person_a = people.get_person_from_user_id(a);
|
|
|
|
var person_b = people.get_person_from_user_id(b);
|
|
|
|
|
|
|
|
var full_name_a = person_a ? person_a.full_name : '';
|
|
|
|
var full_name_b = person_b ? person_b.full_name : '';
|
|
|
|
|
|
|
|
return util.strcmp(full_name_a, full_name_b);
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.sort_users = function (user_ids) {
|
|
|
|
// TODO sort by unread count first, once we support that
|
|
|
|
user_ids.sort(exports.compare_function);
|
|
|
|
return user_ids;
|
|
|
|
};
|
|
|
|
|
|
|
|
function filter_user_ids(filter_text, user_ids) {
|
|
|
|
if (filter_text === '') {
|
|
|
|
return user_ids;
|
|
|
|
}
|
|
|
|
|
2018-12-18 19:29:08 +01:00
|
|
|
user_ids = _.reject(user_ids, people.is_my_user_id);
|
|
|
|
|
2019-03-06 09:20:50 +01:00
|
|
|
var search_terms = filter_text.toLowerCase().split(/[|,]+/);
|
2018-04-19 15:46:56 +02:00
|
|
|
search_terms = _.map(search_terms, function (s) {
|
|
|
|
return s.trim();
|
|
|
|
});
|
|
|
|
|
|
|
|
var persons = _.map(user_ids, function (user_id) {
|
|
|
|
return people.get_person_from_user_id(user_id);
|
|
|
|
});
|
|
|
|
|
|
|
|
var user_id_dict = people.filter_people_by_search_terms(persons, search_terms);
|
|
|
|
return user_id_dict.keys();
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.matches_filter = function (filter_text, user_id) {
|
|
|
|
// This is a roundabout way of checking a user if you look
|
|
|
|
// too hard at it, but it should be fine for now.
|
2018-06-06 18:19:09 +02:00
|
|
|
return filter_user_ids(filter_text, [user_id]).length === 1;
|
2018-04-19 15:46:56 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
function get_num_unread(user_id) {
|
|
|
|
if (unread.suppress_unread_counts) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return unread.num_unread_for_person(user_id);
|
|
|
|
}
|
|
|
|
|
2018-12-21 20:10:27 +01:00
|
|
|
exports.my_user_status = function (user_id) {
|
|
|
|
if (!people.is_my_user_id(user_id)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user_status.is_away(user_id)) {
|
2019-02-14 10:14:35 +01:00
|
|
|
return i18n.t('(unavailable)');
|
2018-12-21 20:10:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return i18n.t('(you)');
|
|
|
|
};
|
|
|
|
|
2019-02-28 16:09:03 +01:00
|
|
|
exports.user_last_seen_time_status = function (user_id) {
|
|
|
|
var status = presence.get_status(user_id);
|
|
|
|
if (status === "active") {
|
2019-03-13 19:21:38 +01:00
|
|
|
return i18n.t("Online now");
|
2019-02-28 16:09:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (page_params.realm_is_zephyr_mirror_realm) {
|
|
|
|
// We don't send presence data to clients in Zephyr mirroring realms
|
|
|
|
return i18n.t("Unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
// There are situations where the client has incomplete presence
|
|
|
|
// history on a user. This can happen when users are deactivated,
|
|
|
|
// or when they just haven't been present in a long time (and we
|
|
|
|
// may have queries on presence that go back only N weeks).
|
|
|
|
//
|
|
|
|
// We give the somewhat vague status of "Unknown" for these users.
|
|
|
|
var last_active_date = presence.last_active_date(user_id);
|
|
|
|
if (last_active_date === undefined) {
|
|
|
|
return i18n.t("More than 2 weeks ago");
|
|
|
|
}
|
|
|
|
return timerender.last_seen_status_from_date(last_active_date.clone());
|
|
|
|
};
|
|
|
|
|
2019-01-25 16:40:18 +01:00
|
|
|
exports.user_title = function (user_id) {
|
|
|
|
var buddy_status = exports.buddy_status(user_id);
|
|
|
|
var type_desc = presence_descriptions[buddy_status];
|
|
|
|
var status_text = user_status.get_status_text(user_id);
|
|
|
|
var person = people.get_person_from_user_id(user_id);
|
|
|
|
var title;
|
|
|
|
|
|
|
|
if (status_text) {
|
|
|
|
// The user-set status, like "out to lunch",
|
|
|
|
// is more important than actual presence.
|
|
|
|
title = status_text;
|
|
|
|
} else {
|
|
|
|
title = person.full_name;
|
|
|
|
if (type_desc) {
|
2019-02-14 10:14:35 +01:00
|
|
|
// example: "Cordelia Lear is unavailable"
|
2019-01-25 16:40:18 +01:00
|
|
|
title += ' ' + type_desc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return title;
|
|
|
|
};
|
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
exports.info_for = function (user_id) {
|
2019-02-17 02:10:42 +01:00
|
|
|
var user_circle_class = exports.get_user_circle_class(user_id);
|
2018-04-19 15:46:56 +02:00
|
|
|
var person = people.get_person_from_user_id(user_id);
|
2018-12-21 20:10:27 +01:00
|
|
|
var my_user_status = exports.my_user_status(user_id);
|
2019-01-25 16:40:18 +01:00
|
|
|
var title = exports.user_title(user_id);
|
2018-04-19 15:46:56 +02:00
|
|
|
|
|
|
|
return {
|
2018-08-04 16:46:17 +02:00
|
|
|
href: hash_util.pm_with_uri(person.email),
|
2018-04-19 15:46:56 +02:00
|
|
|
name: person.full_name,
|
|
|
|
user_id: user_id,
|
2018-12-21 20:10:27 +01:00
|
|
|
my_user_status: my_user_status,
|
2018-11-28 00:07:01 +01:00
|
|
|
is_current_user: people.is_my_user_id(user_id),
|
2018-04-19 15:46:56 +02:00
|
|
|
num_unread: get_num_unread(user_id),
|
2019-02-17 02:10:42 +01:00
|
|
|
user_circle_class: user_circle_class,
|
2019-01-25 16:40:18 +01:00
|
|
|
title: title,
|
2018-04-19 15:46:56 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2018-04-22 17:46:20 +02:00
|
|
|
exports.get_item = function (user_id) {
|
|
|
|
var info = exports.info_for(user_id);
|
|
|
|
compose_fade.update_user_info([info], fade_config);
|
|
|
|
return info;
|
|
|
|
};
|
|
|
|
|
2018-04-20 18:22:28 +02:00
|
|
|
function user_is_recently_active(user_id) {
|
|
|
|
// return true if the user has a green/orange cirle
|
2018-12-20 15:55:20 +01:00
|
|
|
return exports.level(user_id) <= 2;
|
2018-04-20 18:22:28 +02:00
|
|
|
}
|
|
|
|
|
2018-04-23 23:13:52 +02:00
|
|
|
function maybe_shrink_list(user_ids, filter_text) {
|
|
|
|
if (user_ids.length <= exports.max_size_before_shrinking) {
|
|
|
|
return user_ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (filter_text) {
|
|
|
|
// If the user types something, we want to show all
|
|
|
|
// users matching the text, even if they have not been
|
|
|
|
// online recently.
|
|
|
|
// For super common letters like "s", we may
|
|
|
|
// eventually want to filter down to only users that
|
|
|
|
// are in presence.get_user_ids().
|
2018-04-20 18:22:28 +02:00
|
|
|
return user_ids;
|
|
|
|
}
|
|
|
|
|
|
|
|
user_ids = _.filter(user_ids, user_is_recently_active);
|
|
|
|
|
|
|
|
return user_ids;
|
|
|
|
}
|
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
exports.get_filtered_and_sorted_user_ids = function (filter_text) {
|
|
|
|
var user_ids;
|
|
|
|
|
|
|
|
if (filter_text) {
|
|
|
|
// If there's a filter, select from all users, not just those
|
|
|
|
// recently active.
|
|
|
|
user_ids = filter_user_ids(filter_text, people.get_active_user_ids());
|
|
|
|
} else {
|
|
|
|
// From large realms, the user_ids in presence may exclude
|
|
|
|
// users who have been idle more than three weeks. When the
|
|
|
|
// filter text is blank, we show only those recently active users.
|
|
|
|
user_ids = presence.get_user_ids();
|
|
|
|
}
|
|
|
|
|
2018-07-14 14:06:30 +02:00
|
|
|
user_ids = _.filter(user_ids, function (user_id) {
|
|
|
|
var person = people.get_person_from_user_id(user_id);
|
|
|
|
|
|
|
|
if (person) {
|
2018-09-08 14:41:41 +02:00
|
|
|
// if the user is bot, do not show in presence data.
|
|
|
|
if (person.is_bot) {
|
2018-07-14 14:06:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2018-04-20 18:22:28 +02:00
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
|
2018-07-14 14:06:30 +02:00
|
|
|
user_ids = maybe_shrink_list(user_ids, filter_text);
|
2018-04-19 15:46:56 +02:00
|
|
|
|
2018-07-14 14:06:30 +02:00
|
|
|
return exports.sort_users(user_ids);
|
2018-07-16 15:25:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.get_items_for_users = function (user_ids) {
|
2018-04-19 15:46:56 +02:00
|
|
|
var user_info = _.map(user_ids, exports.info_for).filter(function (person) {
|
|
|
|
// filtered bots and yourself are set to "undefined" in the `info_for`
|
|
|
|
// function.
|
|
|
|
return typeof person !== "undefined";
|
|
|
|
});
|
|
|
|
|
2018-04-22 17:46:20 +02:00
|
|
|
compose_fade.update_user_info(user_info, fade_config);
|
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
return user_info;
|
|
|
|
};
|
|
|
|
|
2019-02-18 16:31:30 +01:00
|
|
|
exports.huddle_fraction_present = function (huddle) {
|
|
|
|
var user_ids = huddle.split(',');
|
|
|
|
|
|
|
|
var num_present = 0;
|
|
|
|
_.each(user_ids, function (user_id) {
|
|
|
|
if (presence.is_active(user_id)) {
|
|
|
|
num_present += 1;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (num_present === user_ids.length) {
|
|
|
|
return 1;
|
|
|
|
} else if (num_present !== 0) {
|
|
|
|
return 0.5;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2018-04-19 15:46:56 +02:00
|
|
|
return exports;
|
|
|
|
|
|
|
|
}());
|
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = buddy_data;
|
|
|
|
}
|
2018-05-28 08:04:36 +02:00
|
|
|
window.buddy_data = buddy_data;
|