mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	Add ability to pin streams to top of the streams sidebar list.
Based on work by Lauren Long, with some tweaks by tabbott.
This commit is contained in:
		@@ -120,3 +120,37 @@ global.use_template('stream_privacy');
 | 
			
		||||
 | 
			
		||||
    assert(li.find('.stream-privacy').find("i").hasClass("icon-vector-lock"));
 | 
			
		||||
}());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
(function test_sort_pin_to_top_streams() {
 | 
			
		||||
 | 
			
		||||
    var stream_search_box = $('<input class="stream-list-filter" type="text" placeholder="Search streams">');
 | 
			
		||||
    var stream_filters = $('<ul id="stream_filters">');
 | 
			
		||||
    $("body").empty();
 | 
			
		||||
    $("body").append(stream_search_box);
 | 
			
		||||
    $("body").append(stream_filters);
 | 
			
		||||
 | 
			
		||||
    var develSub = {
 | 
			
		||||
        name: 'devel',
 | 
			
		||||
        stream_id: 1000,
 | 
			
		||||
        color: 'blue',
 | 
			
		||||
        id: 5,
 | 
			
		||||
        pin_to_top: false,
 | 
			
		||||
        subscribed: true,
 | 
			
		||||
        sidebar_li: stream_list.add_stream_to_sidebar('devel')
 | 
			
		||||
    };
 | 
			
		||||
    global.stream_data.add_sub('devel', develSub);
 | 
			
		||||
 | 
			
		||||
    var socialSub = {
 | 
			
		||||
        name: 'social',
 | 
			
		||||
        stream_id: 2000,
 | 
			
		||||
        color: 'green',
 | 
			
		||||
        id: 6,
 | 
			
		||||
        pin_to_top: true,
 | 
			
		||||
        subscribed: true,
 | 
			
		||||
        sidebar_li: stream_list.add_stream_to_sidebar('social')
 | 
			
		||||
    };
 | 
			
		||||
    global.stream_data.add_sub('social', socialSub);
 | 
			
		||||
    stream_list.build_stream_list();
 | 
			
		||||
    assert.equal(socialSub.sidebar_li.nextAll().find('[ data-name="devel"]').length, 1);
 | 
			
		||||
}());
 | 
			
		||||
 
 | 
			
		||||
@@ -559,6 +559,13 @@ exports.register_click_handlers = function () {
 | 
			
		||||
        e.stopPropagation();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('body').on('click', '.pin_to_top', function (e) {
 | 
			
		||||
        var stream = $(e.currentTarget).parents('ul').attr('data-name');
 | 
			
		||||
        popovers.hide_stream_sidebar_popover();
 | 
			
		||||
        subs.toggle_pin_to_top_stream(stream);
 | 
			
		||||
        e.stopPropagation();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('body').on('click', '.open_stream_settings', function (e) {
 | 
			
		||||
        var stream = $(e.currentTarget).parents('ul').attr('data-name');
 | 
			
		||||
        popovers.hide_stream_sidebar_popover();
 | 
			
		||||
 
 | 
			
		||||
@@ -138,6 +138,9 @@ function get_events_success(events) {
 | 
			
		||||
                });
 | 
			
		||||
            } else if (event.op === 'update') {
 | 
			
		||||
                subs.update_subscription_properties(event.name, event.property, event.value);
 | 
			
		||||
                if (event.property === 'pin_to_top') {
 | 
			
		||||
                    subs.pin_or_unpin_stream(event.name);
 | 
			
		||||
                }
 | 
			
		||||
            } else if (event.op === 'peer_add' || event.op === 'peer_remove') {
 | 
			
		||||
                _.each(event.subscriptions, function (sub) {
 | 
			
		||||
                    var js_event_type;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ var private_messages_open = false;
 | 
			
		||||
var last_private_message_count = 0;
 | 
			
		||||
var last_mention_count = 0;
 | 
			
		||||
var previous_sort_order;
 | 
			
		||||
var previous_unpinned_order;
 | 
			
		||||
 | 
			
		||||
function active_stream_name() {
 | 
			
		||||
    if (narrow.active()) {
 | 
			
		||||
@@ -54,8 +55,33 @@ exports.build_stream_list = function () {
 | 
			
		||||
    streams = filter_streams_by_search(streams);
 | 
			
		||||
 | 
			
		||||
    var sort_recent = (streams.length > 40);
 | 
			
		||||
    var pinned_streams = [];
 | 
			
		||||
    var unpinned_streams = [];
 | 
			
		||||
    var parent = $('#stream_filters');
 | 
			
		||||
    var elems = [];
 | 
			
		||||
 | 
			
		||||
    streams.sort(function (a, b) {
 | 
			
		||||
    function add_sidebar_li(stream) {
 | 
			
		||||
        var li = $(stream_data.get_sub(stream).sidebar_li);
 | 
			
		||||
        if (sort_recent) {
 | 
			
		||||
            if (! stream_data.recent_subjects.has(stream)) {
 | 
			
		||||
                li.addClass('inactive_stream');
 | 
			
		||||
            } else {
 | 
			
		||||
                li.removeClass('inactive_stream');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        elems.push(li.get(0));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _.each(streams, function (stream) {
 | 
			
		||||
        var pinned = stream_data.get_sub(stream).pin_to_top;
 | 
			
		||||
        if (pinned) {
 | 
			
		||||
            pinned_streams.push(stream);
 | 
			
		||||
        } else {
 | 
			
		||||
            unpinned_streams.push(stream);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    unpinned_streams.sort(function (a, b) {
 | 
			
		||||
        if (sort_recent) {
 | 
			
		||||
            if (stream_data.recent_subjects.has(b) && ! stream_data.recent_subjects.has(a)) {
 | 
			
		||||
                return 1;
 | 
			
		||||
@@ -66,18 +92,17 @@ exports.build_stream_list = function () {
 | 
			
		||||
        return util.strcmp(a, b);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (previous_sort_order !== undefined
 | 
			
		||||
        && util.array_compare(previous_sort_order, streams)) {
 | 
			
		||||
    streams = pinned_streams.concat(unpinned_streams);
 | 
			
		||||
 | 
			
		||||
    if (previous_sort_order !== undefined && util.array_compare(previous_sort_order, streams)
 | 
			
		||||
                                          && util.array_compare(previous_unpinned_order, unpinned_streams)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    previous_sort_order = streams;
 | 
			
		||||
 | 
			
		||||
    var parent = $('#stream_filters');
 | 
			
		||||
    previous_unpinned_order = unpinned_streams;
 | 
			
		||||
    parent.empty();
 | 
			
		||||
 | 
			
		||||
    var elems = [];
 | 
			
		||||
    _.each(streams, function (stream) {
 | 
			
		||||
    _.each(pinned_streams, function (stream) {
 | 
			
		||||
        var li = $(stream_data.get_sub(stream).sidebar_li);
 | 
			
		||||
        if (sort_recent) {
 | 
			
		||||
            if (! stream_data.recent_subjects.has(stream)) {
 | 
			
		||||
@@ -88,6 +113,15 @@ exports.build_stream_list = function () {
 | 
			
		||||
        }
 | 
			
		||||
        elems.push(li.get(0));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (pinned_streams.length > 0) {
 | 
			
		||||
        _.each(pinned_streams, add_sidebar_li);
 | 
			
		||||
        elems.push($('<hr class="pinned-stream-split">').get(0));
 | 
			
		||||
    }
 | 
			
		||||
    if (unpinned_streams.length > 0) {
 | 
			
		||||
        _.each(unpinned_streams, add_sidebar_li);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $(elems).appendTo(parent);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -121,6 +155,14 @@ function zoom_in() {
 | 
			
		||||
    $("#streams_list").expectOne().removeClass("zoom-out").addClass("zoom-in");
 | 
			
		||||
    zoomed_stream = active_stream_name();
 | 
			
		||||
 | 
			
		||||
    // Hide stream list titles and pinned stream splitter
 | 
			
		||||
    $(".stream-filters-label").each(function () {
 | 
			
		||||
        $(this).hide();
 | 
			
		||||
    });
 | 
			
		||||
    $(".pinned-stream-split").each(function () {
 | 
			
		||||
        $(this).hide();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $("#stream_filters li.narrow-filter").each(function () {
 | 
			
		||||
        var elt = $(this);
 | 
			
		||||
 | 
			
		||||
@@ -135,6 +177,14 @@ function zoom_in() {
 | 
			
		||||
function zoom_out() {
 | 
			
		||||
    popovers.hide_all();
 | 
			
		||||
    zoomed_to_topics = false;
 | 
			
		||||
    // Show stream list titles and pinned stream splitter
 | 
			
		||||
    $(".stream-filters-label").each(function () {
 | 
			
		||||
        $(this).show();
 | 
			
		||||
    });
 | 
			
		||||
    $(".pinned-stream-split").each(function () {
 | 
			
		||||
        $(this).show();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $("#streams_list").expectOne().removeClass("zoom-in").addClass("zoom-out");
 | 
			
		||||
    $("#stream_filters li.narrow-filter").show();
 | 
			
		||||
}
 | 
			
		||||
@@ -188,7 +238,8 @@ function build_stream_sidebar_row(name) {
 | 
			
		||||
                uri: narrow.by_stream_uri(name),
 | 
			
		||||
                not_in_home_view: (stream_data.in_home_view(name) === false),
 | 
			
		||||
                invite_only: sub.invite_only,
 | 
			
		||||
                color: stream_data.get_color(name)
 | 
			
		||||
                color: stream_data.get_color(name),
 | 
			
		||||
                pin_to_top: sub.pin_to_top
 | 
			
		||||
               };
 | 
			
		||||
    args.dark_background = stream_color.get_color_class(args.color);
 | 
			
		||||
    var list_item = $(templates.render('stream_sidebar_row', args));
 | 
			
		||||
@@ -531,6 +582,14 @@ exports.rename_stream = function (sub) {
 | 
			
		||||
    exports.build_stream_list(); // big hammer
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.refresh_stream_in_sidebar = function (sub) {
 | 
			
		||||
    // used by subs.pin_or_unpin_stream,
 | 
			
		||||
    // since pinning/unpinning requires reordering of streams in the sidebar
 | 
			
		||||
    sub.sidebar_li = build_stream_sidebar_row(sub.name);
 | 
			
		||||
    exports.build_stream_list();
 | 
			
		||||
    exports.update_streams_sidebar();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
$(function () {
 | 
			
		||||
    $(document).on('narrow_activated.zulip', function (event) {
 | 
			
		||||
        reset_to_unnarrowed(active_stream_name() === zoomed_stream);
 | 
			
		||||
@@ -608,6 +667,7 @@ $(function () {
 | 
			
		||||
        exports.remove_narrow_filter(stream_name, 'stream');
 | 
			
		||||
        // We need to make sure we resort if the removed sub gets added again
 | 
			
		||||
        previous_sort_order = undefined;
 | 
			
		||||
        previous_unpinned_order = undefined;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('.show-all-streams').on('click', function (e) {
 | 
			
		||||
 
 | 
			
		||||
@@ -144,6 +144,11 @@ exports.toggle_home = function (stream_name) {
 | 
			
		||||
    set_stream_property(stream_name, 'in_home_view', sub.in_home_view);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.toggle_pin_to_top_stream = function (stream_name) {
 | 
			
		||||
    var sub = stream_data.get_sub(stream_name);
 | 
			
		||||
    set_stream_property(stream_name, 'pin_to_top', !sub.pin_to_top);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function update_stream_desktop_notifications(sub, value) {
 | 
			
		||||
    var desktop_notifications_checkbox = $("#subscription_" + sub.stream_id + " #sub_desktop_notifications_setting .sub_setting_control");
 | 
			
		||||
    desktop_notifications_checkbox.attr('checked', value);
 | 
			
		||||
@@ -156,6 +161,12 @@ function update_stream_audible_notifications(sub, value) {
 | 
			
		||||
    sub.audible_notifications = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function update_stream_pin(sub, value) {
 | 
			
		||||
    var pin_checkbox = $('#pinstream-' + sub.stream_id);
 | 
			
		||||
    pin_checkbox.attr('checked', value);
 | 
			
		||||
    sub.pin_to_top = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function update_stream_name(sub, new_name) {
 | 
			
		||||
    // Rename the stream internally.
 | 
			
		||||
    var old_name = sub.name;
 | 
			
		||||
@@ -198,6 +209,14 @@ function stream_audible_notifications_clicked(e) {
 | 
			
		||||
    set_stream_property(stream, 'audible_notifications', sub.audible_notifications);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function stream_pin_clicked(e) {
 | 
			
		||||
    var sub_row = $(e.target).closest('.subscription_row');
 | 
			
		||||
    var stream = sub_row.find('.subscription_name').text();
 | 
			
		||||
 | 
			
		||||
    var sub = stream_data.get_sub(stream);
 | 
			
		||||
    exports.toggle_pin_to_top_stream(stream);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exports.set_color = function (stream_name, color) {
 | 
			
		||||
    var sub = stream_data.get_sub(stream_name);
 | 
			
		||||
    stream_color.update_stream_color(sub, stream_name, color, {update_historical: true});
 | 
			
		||||
@@ -387,6 +406,23 @@ exports.mark_sub_unsubscribed = function (sub) {
 | 
			
		||||
    $(document).trigger($.Event('subscription_remove_done.zulip', {sub: sub}));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.pin_or_unpin_stream = function (stream_name) {
 | 
			
		||||
    var sub = stream_data.get_sub(stream_name);
 | 
			
		||||
    if (stream_name === undefined) {
 | 
			
		||||
        return;
 | 
			
		||||
    } else {
 | 
			
		||||
        stream_list.refresh_stream_in_sidebar(sub);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.sub_pinned_or_unpinned = function (stream_name) {
 | 
			
		||||
    var sub = stream_data.get_sub(stream_name);
 | 
			
		||||
    if (stream_name === undefined) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    return sub.pin_to_top;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.receives_desktop_notifications = function (stream_name) {
 | 
			
		||||
    var sub = stream_data.get_sub(stream_name);
 | 
			
		||||
    if (sub === undefined) {
 | 
			
		||||
@@ -414,6 +450,7 @@ function populate_subscriptions(subs, subscribed) {
 | 
			
		||||
                                           invite_only: elem.invite_only,
 | 
			
		||||
                                           desktop_notifications: elem.desktop_notifications,
 | 
			
		||||
                                           audible_notifications: elem.audible_notifications,
 | 
			
		||||
                                           pin_to_top: elem.pin_to_top,
 | 
			
		||||
                                           subscribed: subscribed,
 | 
			
		||||
                                           email_address: elem.email_address,
 | 
			
		||||
                                           stream_id: elem.stream_id,
 | 
			
		||||
@@ -544,6 +581,9 @@ exports.update_subscription_properties = function (stream_name, property, value)
 | 
			
		||||
    case 'email_address':
 | 
			
		||||
        sub.email_address = value;
 | 
			
		||||
        break;
 | 
			
		||||
    case 'pin_to_top':
 | 
			
		||||
        update_stream_pin(sub, value);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        blueslip.warn("Unexpected subscription property type", {property: property,
 | 
			
		||||
                                                                value: value});
 | 
			
		||||
@@ -874,6 +914,8 @@ $(function () {
 | 
			
		||||
                                 stream_desktop_notifications_clicked);
 | 
			
		||||
    $("#subscriptions_table").on("click", "#sub_audible_notifications_setting",
 | 
			
		||||
                                 stream_audible_notifications_clicked);
 | 
			
		||||
    $("#subscriptions_table").on("click", "#sub_pin_setting",
 | 
			
		||||
                                 stream_pin_clicked);
 | 
			
		||||
 | 
			
		||||
    $("#subscriptions_table").on("submit", ".subscriber_list_add form", function (e) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
 
 | 
			
		||||
@@ -510,6 +510,11 @@ ul.filters {
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.stream-pin-icon {
 | 
			
		||||
    margin-right: 4px !important;
 | 
			
		||||
    margin-left: 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#global_filters .global-filter {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    padding: 1px 10px;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,16 @@
 | 
			
		||||
      {{/if}}
 | 
			
		||||
    </a>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li>
 | 
			
		||||
    <a class="pin_to_top">
 | 
			
		||||
      <i class="icon-vector-pushpin stream-pin-icon"></i>
 | 
			
		||||
      {{#if stream.pin_to_top}}
 | 
			
		||||
      {{#tr this}}Unpin stream <b>__stream.name__</b> from top{{/tr}}
 | 
			
		||||
      {{else}}
 | 
			
		||||
      {{#tr this}}Pin stream <b>__stream.name__</b> to top{{/tr}}
 | 
			
		||||
      {{/if}}
 | 
			
		||||
    </a>
 | 
			
		||||
  </li>
 | 
			
		||||
  <li>
 | 
			
		||||
    <a class="compose_to_stream">
 | 
			
		||||
      <i class="icon-vector-edit"></i>
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,12 @@
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <div id="sub_pin_setting" class="sub_setting_checkbox">
 | 
			
		||||
              <input id="pinstream-{{stream_id}}" class="sub_setting_control" type="checkbox" tabindex="-1" {{#if pin_to_top}}checked{{/if}} />
 | 
			
		||||
              <label class="subscription-control-label">{{t "Pin stream to top<br /> of left sidebar" }}</label>
 | 
			
		||||
            </div>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li>
 | 
			
		||||
            <span class="sub_setting_control">
 | 
			
		||||
              <input stream_name="{{name}}" class="colorpicker" id="streamcolor" type="text" value="{{color}}" tabindex="-1" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1253,6 +1253,7 @@ def notify_subscriptions_added(user_profile, sub_pairs, stream_emails, no_log=Fa
 | 
			
		||||
                    desktop_notifications=subscription.desktop_notifications,
 | 
			
		||||
                    audible_notifications=subscription.audible_notifications,
 | 
			
		||||
                    description=stream.description,
 | 
			
		||||
                    pin_to_top=subscription.pin_to_top,
 | 
			
		||||
                    subscribers=stream_emails(stream))
 | 
			
		||||
            for (subscription, stream) in sub_pairs]
 | 
			
		||||
    event = dict(type="subscription", op="add",
 | 
			
		||||
@@ -2544,7 +2545,7 @@ def gather_subscriptions_helper(user_profile):
 | 
			
		||||
        user_profile    = user_profile,
 | 
			
		||||
        recipient__type = Recipient.STREAM).values(
 | 
			
		||||
        "recipient__type_id", "in_home_view", "color", "desktop_notifications",
 | 
			
		||||
        "audible_notifications", "active")
 | 
			
		||||
        "audible_notifications", "active", "pin_to_top")
 | 
			
		||||
 | 
			
		||||
    stream_ids = [sub["recipient__type_id"] for sub in sub_dicts]
 | 
			
		||||
 | 
			
		||||
@@ -2583,6 +2584,7 @@ def gather_subscriptions_helper(user_profile):
 | 
			
		||||
                       'color': sub["color"],
 | 
			
		||||
                       'desktop_notifications': sub["desktop_notifications"],
 | 
			
		||||
                       'audible_notifications': sub["audible_notifications"],
 | 
			
		||||
                       'pin_to_top': sub["pin_to_top"],
 | 
			
		||||
                       'stream_id': stream["id"],
 | 
			
		||||
                       'description': stream["description"],
 | 
			
		||||
                       'email_address': encode_email_address_helper(stream["name"], stream["email_token"])}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								zerver/migrations/0022_subscription_pin_to_top.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								zerver/migrations/0022_subscription_pin_to_top.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from __future__ import unicode_literals
 | 
			
		||||
 | 
			
		||||
from django.db import models, migrations
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('zerver', '0021_migrate_attachment_data'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='subscription',
 | 
			
		||||
            name='pin_to_top',
 | 
			
		||||
            field=models.BooleanField(default=False),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@@ -1232,6 +1232,7 @@ class Subscription(ModelReprMixin, models.Model):
 | 
			
		||||
 | 
			
		||||
    DEFAULT_STREAM_COLOR = "#c2c2c2"
 | 
			
		||||
    color = models.CharField(max_length=10, default=DEFAULT_STREAM_COLOR) # type: text_type
 | 
			
		||||
    pin_to_top = models.BooleanField(default=False) # type: bool
 | 
			
		||||
 | 
			
		||||
    desktop_notifications = models.BooleanField(default=True) # type: bool
 | 
			
		||||
    audible_notifications = models.BooleanField(default=True) # type: bool
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,7 @@ from zerver.lib.actions import (
 | 
			
		||||
    do_change_full_name,
 | 
			
		||||
    do_change_is_admin,
 | 
			
		||||
    do_change_stream_description,
 | 
			
		||||
    do_change_subscription_property,
 | 
			
		||||
    do_create_user,
 | 
			
		||||
    do_deactivate_user,
 | 
			
		||||
    do_regenerate_api_key,
 | 
			
		||||
@@ -43,6 +44,7 @@ from zerver.lib.actions import (
 | 
			
		||||
    do_change_twenty_four_hour_time,
 | 
			
		||||
    do_change_left_side_userlist,
 | 
			
		||||
    fetch_initial_state_data,
 | 
			
		||||
    get_subscription
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from zerver.lib.event_queue import allocate_client_descriptor
 | 
			
		||||
@@ -488,6 +490,22 @@ class EventsRegisterTest(AuthedTestCase):
 | 
			
		||||
            error = schema_checker('events[0]', events[0])
 | 
			
		||||
            self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_change_pin_stream(self):
 | 
			
		||||
        # type: () -> None
 | 
			
		||||
        schema_checker = check_dict([
 | 
			
		||||
            ('type', equals('subscription')),
 | 
			
		||||
            ('op', equals('update')),
 | 
			
		||||
            ('property', equals('pin_to_top')),
 | 
			
		||||
            ('value', check_bool),
 | 
			
		||||
        ])
 | 
			
		||||
        stream = "Denmark"
 | 
			
		||||
        sub = get_subscription(stream, self.user_profile)
 | 
			
		||||
        # The first False is probably a noop, then we get transitions in both directions.
 | 
			
		||||
        for pinned in (False, True, False):
 | 
			
		||||
            events = self.do_test(lambda: do_change_subscription_property(self.user_profile, sub, stream, "pin_to_top", pinned))
 | 
			
		||||
            error = schema_checker('events[0]', events[0])
 | 
			
		||||
            self.assert_on_error(error)
 | 
			
		||||
 | 
			
		||||
    def test_change_is_admin(self):
 | 
			
		||||
        # type: () -> None
 | 
			
		||||
        schema_checker = check_dict([
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ from zerver.lib.actions import (
 | 
			
		||||
    create_stream_if_needed, do_add_default_stream, do_add_subscription, do_change_is_admin,
 | 
			
		||||
    do_create_realm, do_remove_default_stream, do_set_realm_create_stream_by_admins_only,
 | 
			
		||||
    gather_subscriptions, get_default_streams_for_realm, get_realm, get_stream,
 | 
			
		||||
    get_user_profile_by_email, set_default_streams,
 | 
			
		||||
    get_user_profile_by_email, set_default_streams, get_subscription
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
@@ -591,6 +591,33 @@ class SubscriptionPropertiesTest(AuthedTestCase):
 | 
			
		||||
        self.assert_json_error(
 | 
			
		||||
            result, "value key is missing from subscription_data[0]")
 | 
			
		||||
 | 
			
		||||
    def test_set_pin_to_top(self):
 | 
			
		||||
        # type: () -> None
 | 
			
		||||
        """
 | 
			
		||||
        A POST request to /json/subscriptions/property with stream_name and
 | 
			
		||||
        pin_to_top data pins the stream.
 | 
			
		||||
        """
 | 
			
		||||
        test_email = "hamlet@zulip.com"
 | 
			
		||||
        self.login(test_email)
 | 
			
		||||
 | 
			
		||||
        user_profile = get_user_profile_by_email(test_email)
 | 
			
		||||
        old_subs, _ = gather_subscriptions(user_profile)
 | 
			
		||||
        sub = old_subs[0]
 | 
			
		||||
        stream_name = sub['name']
 | 
			
		||||
        new_pin_to_top = not sub['pin_to_top']
 | 
			
		||||
        result = self.client.post(
 | 
			
		||||
            "/json/subscriptions/property",
 | 
			
		||||
            {"subscription_data": ujson.dumps([{"property": "pin_to_top",
 | 
			
		||||
                                                "stream": stream_name,
 | 
			
		||||
                                                "value": new_pin_to_top}])})
 | 
			
		||||
 | 
			
		||||
        self.assert_json_success(result)
 | 
			
		||||
 | 
			
		||||
        updated_sub = get_subscription(stream_name, user_profile)
 | 
			
		||||
 | 
			
		||||
        self.assertIsNotNone(updated_sub)
 | 
			
		||||
        self.assertEqual(updated_sub.pin_to_top, new_pin_to_top)
 | 
			
		||||
 | 
			
		||||
    def test_set_invalid_property(self):
 | 
			
		||||
        # type: () -> None
 | 
			
		||||
        """
 | 
			
		||||
 
 | 
			
		||||
@@ -488,7 +488,8 @@ def json_subscription_property(request, user_profile, subscription_data=REQ(
 | 
			
		||||
 | 
			
		||||
    property_converters = {"color": check_string, "in_home_view": check_bool,
 | 
			
		||||
                           "desktop_notifications": check_bool,
 | 
			
		||||
                           "audible_notifications": check_bool}
 | 
			
		||||
                           "audible_notifications": check_bool,
 | 
			
		||||
                           "pin_to_top": check_bool}
 | 
			
		||||
    response_data = []
 | 
			
		||||
 | 
			
		||||
    for change in subscription_data:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user