mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	There are also one or two places we don't need to use it for security purposes, but we do so for consistencey. (imported from commit aa111f5a22a0e8597ec3cf8504adae66d5fb6768)
		
			
				
	
	
		
			174 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var activity = (function () {
 | 
						|
var exports = {};
 | 
						|
 | 
						|
/*
 | 
						|
    Helpers for detecting user activity and managing user idle states
 | 
						|
*/
 | 
						|
 | 
						|
/* After this amount of no activity, mark you idle regardless of your focus */
 | 
						|
var DEFAULT_IDLE_TIMEOUT_MS = 30 * 60 * 1000;
 | 
						|
/* Time between keep-alive pings */
 | 
						|
var ACTIVE_PING_INTERVAL_MS = 60 * 1000;
 | 
						|
 | 
						|
/* Timeouts for away and idle state */
 | 
						|
var AWAY_THRESHOLD_SECS = 10 * 60;
 | 
						|
var IDLE_THRESHOLD_SECS = DEFAULT_IDLE_TIMEOUT_MS / 1000;
 | 
						|
 | 
						|
/* Keep in sync with views.py:json_update_active_status() */
 | 
						|
var ACTIVE = "active";
 | 
						|
var IDLE = "idle";
 | 
						|
 | 
						|
var has_focus = true;
 | 
						|
var ping_timer;
 | 
						|
 | 
						|
var user_info = {};
 | 
						|
 | 
						|
function sort_users(users, user_info) {
 | 
						|
    // TODO sort by unread count first, once we support that
 | 
						|
    users.sort(function (a, b) {
 | 
						|
        if (user_info[a] === 'active' && user_info[b] !== 'active') {
 | 
						|
            return -1;
 | 
						|
        } else if (user_info[b] === 'active' && user_info[a] !== 'active') {
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
 | 
						|
        if (user_info[a] === 'away' && user_info[b] !== 'away') {
 | 
						|
            return -1;
 | 
						|
        } else if (user_info[b] === 'away' && user_info[a] !== 'away') {
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
 | 
						|
        // Sort equivalent PM names alphabetically
 | 
						|
        var full_name_a = a;
 | 
						|
        var full_name_b = b;
 | 
						|
        if (people_dict.has(a)) {
 | 
						|
            full_name_a = people_dict.get(a).full_name;
 | 
						|
        }
 | 
						|
        if (people_dict.has(b)) {
 | 
						|
            full_name_b = people_dict.get(b).full_name;
 | 
						|
        }
 | 
						|
        return util.strcmp(full_name_a, full_name_b);
 | 
						|
    });
 | 
						|
 | 
						|
    return users;
 | 
						|
}
 | 
						|
 | 
						|
// for testing:
 | 
						|
exports._sort_users = sort_users;
 | 
						|
 | 
						|
function focus_lost() {
 | 
						|
    if (!has_focus) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    has_focus = false;
 | 
						|
 | 
						|
    clearInterval(ping_timer);
 | 
						|
    ping_timer = undefined;
 | 
						|
 | 
						|
    $.post('/json/update_active_status', {status: IDLE});
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
function update_users() {
 | 
						|
    var users = sort_users(Object.keys(user_info), user_info);
 | 
						|
    ui.set_presence_list(users, user_info);
 | 
						|
}
 | 
						|
 | 
						|
function status_from_timestamp(baseline_time, presence) {
 | 
						|
    if (presence.website === undefined) {
 | 
						|
        return 'idle';
 | 
						|
    }
 | 
						|
 | 
						|
    var age = baseline_time - presence.website.timestamp;
 | 
						|
 | 
						|
    var status = 'idle';
 | 
						|
    if (presence.website.status === ACTIVE && age >= 0) {
 | 
						|
        if (age < AWAY_THRESHOLD_SECS) {
 | 
						|
            status = 'active';
 | 
						|
        } else if (age < IDLE_THRESHOLD_SECS) {
 | 
						|
            status = 'away';
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return status;
 | 
						|
}
 | 
						|
 | 
						|
function focus_ping() {
 | 
						|
    if (!has_focus) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    $.post('/json/update_active_status', {status: ACTIVE}, function (data) {
 | 
						|
        if (data === undefined || data.presences === undefined) {
 | 
						|
            // We sometimes receive no data even on successful
 | 
						|
            // requests; we should figure out why but this will
 | 
						|
            // prevent us from throwing errors until then
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        user_info = {};
 | 
						|
 | 
						|
        // Update Zephyr mirror activity warning
 | 
						|
        if (data.zephyr_mirror_active === false) {
 | 
						|
            $('#zephyr-mirror-error').show();
 | 
						|
        } else {
 | 
						|
            $('#zephyr-mirror-error').hide();
 | 
						|
        }
 | 
						|
 | 
						|
        // Ping returns the active peer list
 | 
						|
        _.each(data.presences, function (presence, this_email) {
 | 
						|
            if (page_params.email !== this_email) {
 | 
						|
                user_info[this_email] = status_from_timestamp(data.server_timestamp, presence);
 | 
						|
            }
 | 
						|
        });
 | 
						|
        update_users();
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
function focus_gained() {
 | 
						|
    if (!has_focus) {
 | 
						|
        has_focus = true;
 | 
						|
        ping_timer = setInterval(focus_ping, ACTIVE_PING_INTERVAL_MS);
 | 
						|
 | 
						|
        focus_ping();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
exports.initialize = function () {
 | 
						|
    $(window).focus(focus_gained);
 | 
						|
    $(window).idle({idle: DEFAULT_IDLE_TIMEOUT_MS,
 | 
						|
                onIdle: focus_lost,
 | 
						|
                onActive: focus_gained,
 | 
						|
                keepTracking: true});
 | 
						|
 | 
						|
    ping_timer = setInterval(focus_ping, ACTIVE_PING_INTERVAL_MS);
 | 
						|
 | 
						|
    focus_ping();
 | 
						|
};
 | 
						|
 | 
						|
// Set user statuses. `users` should be an object with user emails as keys
 | 
						|
// and presence information (see `status_from_timestamp`) as values.
 | 
						|
//
 | 
						|
// The object does not need to include every user, only the ones
 | 
						|
// whose presence you wish to update.
 | 
						|
//
 | 
						|
// This rerenders the user sidebar at the end, which can be slow if done too
 | 
						|
// often, so try to avoid calling this repeatedly.
 | 
						|
exports.set_user_statuses = function (users, server_time) {
 | 
						|
    _.each(users, function (presence, email) {
 | 
						|
        if (email === page_params.email) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        user_info[email] = status_from_timestamp(server_time, presence);
 | 
						|
    });
 | 
						|
 | 
						|
    update_users();
 | 
						|
};
 | 
						|
 | 
						|
return exports;
 | 
						|
 | 
						|
}());
 | 
						|
if (typeof module !== 'undefined') {
 | 
						|
    module.exports = activity;
 | 
						|
}
 |