mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	We get events to delete subscribers for streams we are not necessarily subscribed to, and it is now important to process those events to produce the correct UI for showing the number of subscribers to streams.
		
			
				
	
	
		
			299 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
var stream_data = (function () {
 | 
						|
 | 
						|
var exports = {};
 | 
						|
 | 
						|
 | 
						|
// The stream_info variable maps stream names to stream properties objects
 | 
						|
// Call clear_subscriptions() to initialize it.
 | 
						|
var stream_info;
 | 
						|
var subs_by_stream_id;
 | 
						|
 | 
						|
exports.clear_subscriptions = function () {
 | 
						|
    stream_info = new Dict({fold_case: true});
 | 
						|
    subs_by_stream_id = new Dict();
 | 
						|
};
 | 
						|
 | 
						|
exports.recent_subjects = new Dict({fold_case: true});
 | 
						|
exports.clear_subscriptions();
 | 
						|
 | 
						|
 | 
						|
exports.add_sub = function (stream_name, sub) {
 | 
						|
    stream_info.set(stream_name, sub);
 | 
						|
    subs_by_stream_id.set(sub.stream_id, sub);
 | 
						|
};
 | 
						|
 | 
						|
exports.get_sub = function (stream_name) {
 | 
						|
    return stream_info.get(stream_name);
 | 
						|
};
 | 
						|
 | 
						|
exports.get_sub_by_id = function (stream_id) {
 | 
						|
    return subs_by_stream_id.get(stream_id);
 | 
						|
};
 | 
						|
 | 
						|
exports.delete_sub = function (stream_name) {
 | 
						|
    stream_info.del(stream_name);
 | 
						|
};
 | 
						|
 | 
						|
exports.subscribed_subs = function () {
 | 
						|
    return _.where(stream_info.values(), {subscribed: true});
 | 
						|
};
 | 
						|
 | 
						|
exports.subscribed_streams = function () {
 | 
						|
    return _.pluck(exports.subscribed_subs(), 'name');
 | 
						|
};
 | 
						|
 | 
						|
exports.get_colors = function () {
 | 
						|
    return _.pluck(exports.subscribed_subs(), 'color');
 | 
						|
};
 | 
						|
 | 
						|
exports.all_subscribed_streams_are_in_home_view = function () {
 | 
						|
    return _.every(exports.subscribed_subs(), function (sub) {
 | 
						|
        return sub.in_home_view; }
 | 
						|
    );
 | 
						|
};
 | 
						|
 | 
						|
exports.home_view_stream_names = function () {
 | 
						|
    var home_view_subs = _.filter(exports.subscribed_subs(), function (sub) {
 | 
						|
            return sub.in_home_view;
 | 
						|
        }
 | 
						|
    );
 | 
						|
    return _.map(home_view_subs, function (sub) {
 | 
						|
        return sub.name;
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
exports.canonicalized_name = function (stream_name) {
 | 
						|
   return stream_name.toString().toLowerCase();
 | 
						|
};
 | 
						|
 | 
						|
exports.get_color = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub === undefined) {
 | 
						|
        return stream_color.default_color;
 | 
						|
    }
 | 
						|
    return sub.color;
 | 
						|
};
 | 
						|
 | 
						|
exports.in_home_view = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    return sub !== undefined && sub.in_home_view;
 | 
						|
};
 | 
						|
 | 
						|
exports.is_subscribed = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    return sub !== undefined && sub.subscribed;
 | 
						|
};
 | 
						|
 | 
						|
exports.get_invite_only = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub === undefined) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    return sub.invite_only;
 | 
						|
};
 | 
						|
 | 
						|
exports.get_name = function (stream_name) {
 | 
						|
    // This returns the actual name of a stream if we are subscribed to
 | 
						|
    // it (i.e "Denmark" vs. "denmark"), while falling thru to
 | 
						|
    // stream_name if we don't have a subscription.  (Stream names
 | 
						|
    // are case-insensitive, but we try to display the actual name
 | 
						|
    // when we know it.)
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub === undefined) {
 | 
						|
        return stream_name;
 | 
						|
    }
 | 
						|
    return sub.name;
 | 
						|
};
 | 
						|
 | 
						|
exports.set_subscribers = function (sub, emails) {
 | 
						|
    sub.subscribers = Dict.from_array(emails || [], {fold_case: true});
 | 
						|
};
 | 
						|
 | 
						|
exports.add_subscriber = function (stream_name, user_email) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (typeof sub === 'undefined') {
 | 
						|
        blueslip.warn("We got an add_subscriber call for a non-existent stream.");
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    sub.subscribers.set(user_email, true);
 | 
						|
};
 | 
						|
 | 
						|
exports.remove_subscriber = function (stream_name, user_email) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (typeof sub === 'undefined') {
 | 
						|
        blueslip.warn("We got a remove_subscriber call for a non-existent stream " + stream_name);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    sub.subscribers.del(user_email);
 | 
						|
};
 | 
						|
 | 
						|
exports.user_is_subscribed = function (stream_name, user_email) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (typeof sub === 'undefined' || !sub.subscribed) {
 | 
						|
        // If we don't know about the stream, or we ourselves are not
 | 
						|
        // subscribed, we can't keep track of the subscriber list in general,
 | 
						|
        // so we return undefined (treated as falsy if not explicitly handled).
 | 
						|
        blueslip.warn("We got a user_is_subscribed call for a non-existent or unsubscribed stream.");
 | 
						|
        return undefined;
 | 
						|
    }
 | 
						|
    return sub.subscribers.has(user_email);
 | 
						|
};
 | 
						|
 | 
						|
exports.create_streams = function (streams) {
 | 
						|
    _.each(streams, function (stream) {
 | 
						|
        var attrs = _.defaults(stream, {
 | 
						|
            subscribed: false
 | 
						|
        });
 | 
						|
        exports.create_sub_from_server_data(stream.name, attrs);
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
exports.create_sub_from_server_data = function (stream_name, attrs) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub !== undefined) {
 | 
						|
        // We've already created this subscription, no need to continue.
 | 
						|
        return sub;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!attrs.stream_id) {
 | 
						|
        // fail fast (blueslip.fatal will throw an error on our behalf)
 | 
						|
        blueslip.fatal("We cannot create a sub without a stream_id");
 | 
						|
        return; // this line is never actually reached
 | 
						|
    }
 | 
						|
 | 
						|
    // Our internal data structure for subscriptions is mostly plain dictionaries,
 | 
						|
    // so we just reuse the attrs that are passed in to us, but we encapsulate how
 | 
						|
    // we handle subscribers.
 | 
						|
    var subscriber_emails = attrs.subscribers;
 | 
						|
    var raw_attrs = _.omit(attrs, 'subscribers');
 | 
						|
 | 
						|
    sub = _.defaults(raw_attrs, {
 | 
						|
        name: stream_name,
 | 
						|
        render_subscribers: !page_params.is_zephyr_mirror_realm || attrs.invite_only === true,
 | 
						|
        subscribed: true,
 | 
						|
        in_home_view: true,
 | 
						|
        invite_only: false,
 | 
						|
        desktop_notifications: page_params.stream_desktop_notifications_enabled,
 | 
						|
        audible_notifications: page_params.stream_sounds_enabled,
 | 
						|
        description: ''
 | 
						|
    });
 | 
						|
 | 
						|
    exports.set_subscribers(sub, subscriber_emails);
 | 
						|
 | 
						|
    if (!sub.color) {
 | 
						|
        var used_colors = exports.get_colors();
 | 
						|
        sub.color = stream_color.pick_color(used_colors);
 | 
						|
    }
 | 
						|
 | 
						|
    exports.add_sub(stream_name, sub);
 | 
						|
 | 
						|
    return sub;
 | 
						|
};
 | 
						|
 | 
						|
exports.receives_desktop_notifications = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub === undefined) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    return sub.desktop_notifications;
 | 
						|
};
 | 
						|
 | 
						|
exports.receives_audible_notifications = function (stream_name) {
 | 
						|
    var sub = exports.get_sub(stream_name);
 | 
						|
    if (sub === undefined) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    return sub.audible_notifications;
 | 
						|
};
 | 
						|
 | 
						|
exports.add_admin_options = function (sub) {
 | 
						|
    return _.extend(sub, {
 | 
						|
        'is_admin': page_params.is_admin,
 | 
						|
        'can_make_public': page_params.is_admin && sub.invite_only && sub.subscribed,
 | 
						|
        'can_make_private': page_params.is_admin && !sub.invite_only
 | 
						|
    });
 | 
						|
};
 | 
						|
 | 
						|
exports.get_streams_for_settings_page = function (public_streams) {
 | 
						|
    // Build up our list of subscribed streams from the data we already have.
 | 
						|
    var subscribed_rows = exports.subscribed_subs();
 | 
						|
 | 
						|
    // To avoid dups, build a set of names we already subscribed to.
 | 
						|
    var subscribed_set = new Dict({fold_case: true});
 | 
						|
    _.each(subscribed_rows, function (sub) {
 | 
						|
        subscribed_set.set(sub.name, true);
 | 
						|
    });
 | 
						|
 | 
						|
    // Right now the back end gives us all public streams; we really only
 | 
						|
    // need to add the ones we haven't already subscribed to.
 | 
						|
    var unsubscribed_streams = _.reject(public_streams.streams, function (stream) {
 | 
						|
        return subscribed_set.has(stream.name);
 | 
						|
    });
 | 
						|
 | 
						|
    // Build up our list of unsubscribed rows.
 | 
						|
    var unsubscribed_rows = [];
 | 
						|
    _.each(unsubscribed_streams, function (stream) {
 | 
						|
        var sub = exports.get_sub(stream.name);
 | 
						|
        if (!sub) {
 | 
						|
            sub = exports.create_sub_from_server_data(
 | 
						|
                    stream.name,
 | 
						|
                    _.extend({subscribed: false}, stream));
 | 
						|
        }
 | 
						|
        unsubscribed_rows.push(sub);
 | 
						|
    });
 | 
						|
 | 
						|
    // Sort and combine all our streams.
 | 
						|
    function by_name(a,b) {
 | 
						|
        return util.strcmp(a.name, b.name);
 | 
						|
    }
 | 
						|
    subscribed_rows.sort(by_name);
 | 
						|
    unsubscribed_rows.sort(by_name);
 | 
						|
    var all_subs = subscribed_rows.concat(unsubscribed_rows);
 | 
						|
 | 
						|
    // Add in admin options.
 | 
						|
    var sub_rows = [];
 | 
						|
    _.each(all_subs, function (sub) {
 | 
						|
        sub = exports.add_admin_options(sub);
 | 
						|
        sub_rows.push(sub);
 | 
						|
    });
 | 
						|
 | 
						|
    return sub_rows;
 | 
						|
};
 | 
						|
 | 
						|
exports.initialize_from_page_params = function () {
 | 
						|
    function populate_subscriptions(subs, subscribed) {
 | 
						|
        subs.forEach(function (sub) {
 | 
						|
            var stream_name = sub.name;
 | 
						|
            sub.subscribed = subscribed;
 | 
						|
 | 
						|
            // When we get subscriber lists from the back end,
 | 
						|
            // they are sent as user ids to save bandwidth,
 | 
						|
            // but the legacy JS code wants emails.
 | 
						|
            if (sub.subscribers) {
 | 
						|
                sub.subscribers = _.map(sub.subscribers, function (subscription) {
 | 
						|
                    return page_params.email_dict[subscription];
 | 
						|
                });
 | 
						|
            }
 | 
						|
            exports.create_sub_from_server_data(stream_name, sub);
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    populate_subscriptions(page_params.subbed_info, true);
 | 
						|
    populate_subscriptions(page_params.unsubbed_info, false);
 | 
						|
    populate_subscriptions(page_params.neversubbed_info, false);
 | 
						|
 | 
						|
    // Garbage collect data structures that were only used for initialization.
 | 
						|
    delete page_params.subbed_info;
 | 
						|
    delete page_params.unsubbed_info;
 | 
						|
    delete page_params.neversubbed_info;
 | 
						|
    delete page_params.email_dict;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
return exports;
 | 
						|
 | 
						|
}());
 | 
						|
if (typeof module !== 'undefined') {
 | 
						|
    module.exports = stream_data;
 | 
						|
}
 |