mirror of https://github.com/zulip/zulip.git
stream-settings: Handle invalid urls correctly.
There were couple of problems in our handling of invalid or incomplete URLs- - The browser back button behavior breaks if someone enters url with invalid or inaccessible stream ID, incorrect stream name, "#streams/new" url without permission to create streams. - On typing stream edit URLs with incorrect right side tab or without any right side tab, we showed "general" section, which is fine, but the URL was still incorrect. This commit fixes the above mentioned problems- - We now update the right side tab to "general" if right side tab is invalid or there is no right side tab. - All the URL updates to fix invalid urls are done using "history.replaceState" to make sure the browser back button behaves as expected. - All the code for checking the urls is done in hashchange.js itself, so we can remove some code from change_state.
This commit is contained in:
parent
7da8f9650c
commit
eea5ee8923
|
@ -1,7 +1,10 @@
|
||||||
import * as internal_url from "../shared/src/internal_url";
|
import * as internal_url from "../shared/src/internal_url";
|
||||||
|
|
||||||
|
import * as blueslip from "./blueslip";
|
||||||
import type {Message} from "./message_store";
|
import type {Message} from "./message_store";
|
||||||
|
import {page_params} from "./page_params";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
|
import * as settings_data from "./settings_data";
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
import * as sub_store from "./sub_store";
|
import * as sub_store from "./sub_store";
|
||||||
import type {StreamSubscription} from "./sub_store";
|
import type {StreamSubscription} from "./sub_store";
|
||||||
|
@ -188,3 +191,50 @@ export function parse_narrow(hash: string): Term[] | undefined {
|
||||||
}
|
}
|
||||||
return terms;
|
return terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function validate_stream_settings_hash(hash: string): string {
|
||||||
|
const hash_components = hash.slice(1).split(/\//);
|
||||||
|
const section = hash_components[1];
|
||||||
|
|
||||||
|
const can_create_streams =
|
||||||
|
settings_data.user_can_create_public_streams() ||
|
||||||
|
settings_data.user_can_create_web_public_streams() ||
|
||||||
|
settings_data.user_can_create_private_streams();
|
||||||
|
if (section === "new" && !can_create_streams) {
|
||||||
|
return "#streams/subscribed";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/\d+/.test(section)) {
|
||||||
|
const stream_id = Number.parseInt(section, 10);
|
||||||
|
const sub = sub_store.get(stream_id);
|
||||||
|
// There are a few situations where we can't display stream settings:
|
||||||
|
// 1. This is a stream that's been archived. (sub=undefined)
|
||||||
|
// 2. The stream ID is invalid. (sub=undefined)
|
||||||
|
// 3. The current user is a guest, and was unsubscribed from the stream
|
||||||
|
// stream in the current session. (In future sessions, the stream will
|
||||||
|
// not be in sub_store).
|
||||||
|
//
|
||||||
|
// In all these cases we redirect the user to 'subscribed' tab.
|
||||||
|
if (sub === undefined || (page_params.is_guest && !stream_data.is_subscribed(stream_id))) {
|
||||||
|
return "#streams/subscribed";
|
||||||
|
}
|
||||||
|
|
||||||
|
const stream_name = hash_components[2];
|
||||||
|
let right_side_tab = hash_components[3];
|
||||||
|
const valid_right_side_tab_values = new Set(["general", "personal", "subscribers"]);
|
||||||
|
if (sub.name === stream_name && valid_right_side_tab_values.has(right_side_tab)) {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
if (!valid_right_side_tab_values.has(right_side_tab)) {
|
||||||
|
right_side_tab = "general";
|
||||||
|
}
|
||||||
|
return stream_edit_url(sub, right_side_tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
const valid_section_values = ["new", "subscribed", "all"];
|
||||||
|
if (!valid_section_values.includes(section)) {
|
||||||
|
blueslip.warn("invalid section for streams: " + section);
|
||||||
|
return "#streams/subscribed";
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
|
@ -240,8 +240,12 @@ function do_hashchange_overlay(old_hash) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base === "streams" && !section) {
|
if (base === "streams") {
|
||||||
history.replaceState(null, "", browser_history.get_full_url("streams/subscribed"));
|
const valid_hash = hash_util.validate_stream_settings_hash(window.location.hash);
|
||||||
|
if (valid_hash !== window.location.hash) {
|
||||||
|
history.replaceState(null, "", browser_history.get_full_url(valid_hash));
|
||||||
|
section = hash_parser.get_current_hash_section();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base === "groups" && !section) {
|
if (base === "groups" && !section) {
|
||||||
|
|
|
@ -702,17 +702,8 @@ function show_right_section() {
|
||||||
export function change_state(section, right_side_tab) {
|
export function change_state(section, right_side_tab) {
|
||||||
// if in #streams/new form.
|
// if in #streams/new form.
|
||||||
if (section === "new") {
|
if (section === "new") {
|
||||||
const can_create_streams =
|
do_open_create_stream();
|
||||||
settings_data.user_can_create_private_streams() ||
|
show_right_section();
|
||||||
settings_data.user_can_create_public_streams() ||
|
|
||||||
settings_data.user_can_create_web_public_streams();
|
|
||||||
if (can_create_streams) {
|
|
||||||
do_open_create_stream();
|
|
||||||
show_right_section();
|
|
||||||
} else {
|
|
||||||
toggler.goto("subscribed");
|
|
||||||
stream_edit.empty_right_panel();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,36 +713,15 @@ export function change_state(section, right_side_tab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (section === "subscribed") {
|
|
||||||
toggler.goto("subscribed");
|
|
||||||
stream_edit.empty_right_panel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the section is a valid number.
|
// if the section is a valid number.
|
||||||
if (/\d+/.test(section)) {
|
if (/\d+/.test(section)) {
|
||||||
const stream_id = Number.parseInt(section, 10);
|
const stream_id = Number.parseInt(section, 10);
|
||||||
const sub = sub_store.get(stream_id);
|
show_right_section();
|
||||||
// There are a few situations where we can't display stream settings:
|
stream_edit_toggler.set_select_tab(right_side_tab);
|
||||||
// 1. This is a stream that's been archived. (sub=undefined)
|
switch_to_stream_row(stream_id);
|
||||||
// 2. The stream ID is invalid. (sub=undefined)
|
|
||||||
// 3. The current user is a guest, and was unsubscribed from the stream
|
|
||||||
// stream in the current session. (In future sessions, the stream will
|
|
||||||
// not be in sub_store).
|
|
||||||
//
|
|
||||||
// In all these cases we redirect the user to 'subscribed' tab.
|
|
||||||
if (!sub || (current_user.is_guest && !stream_data.is_subscribed(stream_id))) {
|
|
||||||
toggler.goto("subscribed");
|
|
||||||
stream_edit.empty_right_panel();
|
|
||||||
} else {
|
|
||||||
show_right_section();
|
|
||||||
stream_edit_toggler.set_select_tab(right_side_tab);
|
|
||||||
switch_to_stream_row(stream_id);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
blueslip.warn("invalid section for streams: " + section);
|
|
||||||
toggler.goto("subscribed");
|
toggler.goto("subscribed");
|
||||||
stream_edit.empty_right_panel();
|
stream_edit.empty_right_panel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -260,7 +260,7 @@ run_test("hash_interactions", ({override, override_rewire}) => {
|
||||||
[ui_report, "error"],
|
[ui_report, "error"],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
window.location.hash = "#streams/whatever";
|
window.location.hash = "#streams/subscribed";
|
||||||
|
|
||||||
helper.clear_events();
|
helper.clear_events();
|
||||||
$window_stub.trigger("hashchange");
|
$window_stub.trigger("hashchange");
|
||||||
|
|
Loading…
Reference in New Issue