streams: Add API endpoint to get stream email.

This commit adds new API endpoint to get stream email which is
used by the web-app as well to get the email when a user tries
to open the stream email modal.

The stream email is returned only to the users who have access
to it. Specifically for private streams only subscribed users
have access to its email. And for public streams, all non-guest
users and only subscribed guests have access to its email.
All users can access email of web-public streams.
This commit is contained in:
Sahil Batra
2023-09-29 23:24:03 +05:30
committed by Alex Vandiver
parent 0a3800332f
commit 6e119842bd
11 changed files with 260 additions and 64 deletions

View File

@@ -496,6 +496,13 @@ export function can_toggle_subscription(sub) {
);
}
export function can_access_stream_email(sub) {
return (
(sub.subscribed || sub.is_web_public || (!page_params.is_guest && !sub.invite_only)) &&
!page_params.is_spectator
);
}
export function can_access_topic_history(sub) {
// Anyone can access topic history for web-public streams and
// subscriptions; additionally, members can access history for

View File

@@ -240,6 +240,7 @@ export function show_settings_for(node) {
page_params.realm_org_type === settings_config.all_org_type_values.business.code,
is_admin: page_params.is_admin,
org_level_message_retention_setting: get_display_text_for_realm_message_retention_setting(),
can_access_stream_email: stream_data.can_access_stream_email(sub),
});
scroll_util.get_content_element($("#stream_settings")).html(html);
@@ -400,6 +401,66 @@ export function get_stream_email_address(flags, address) {
return clean_address.replace("@", flag_string + "@");
}
function show_stream_email_address_modal(address) {
const copy_email_address_modal_html = render_copy_email_address_modal({
email_address: address,
tags: [
{
name: "show-sender",
description: $t({
defaultMessage: "The sender's email address",
}),
},
{
name: "include-footer",
description: $t({defaultMessage: "Email footers (e.g., signature)"}),
},
{
name: "include-quotes",
description: $t({defaultMessage: "Quoted original email (in replies)"}),
},
{
name: "prefer-html",
description: $t({
defaultMessage: "Use html encoding (not recommended)",
}),
},
],
});
dialog_widget.launch({
html_heading: $t_html({defaultMessage: "Generate stream email address"}),
html_body: copy_email_address_modal_html,
id: "copy_email_address_modal",
html_submit_button: $t_html({defaultMessage: "Copy address"}),
html_exit_button: $t_html({defaultMessage: "Close"}),
help_link: "/help/message-a-stream-by-email#configuration-options",
on_click() {},
close_on_submit: false,
});
$("#show-sender").prop("checked", true);
new ClipboardJS("#copy_email_address_modal .dialog_submit_button", {
text() {
return address;
},
});
$("#copy_email_address_modal .tag-checkbox").on("change", () => {
const $checked_checkboxes = $(".copy-email-modal").find("input:checked");
const flags = [];
$($checked_checkboxes).each(function () {
flags.push($(this).attr("id"));
});
address = get_stream_email_address(flags, address);
$(".email-address").text(address);
});
}
export function initialize() {
$("#main_div").on("click", ".stream_sub_unsub_button", (e) => {
e.preventDefault();
@@ -480,64 +541,20 @@ export function initialize() {
e.stopPropagation();
const stream_id = get_stream_id(e.target);
const stream = sub_store.get(stream_id);
let address = stream.email_address;
const copy_email_address = render_copy_email_address_modal({
email_address: address,
tags: [
{
name: "show-sender",
description: $t({
defaultMessage: "The sender's email address",
}),
},
{
name: "include-footer",
description: $t({defaultMessage: "Email footers (e.g., signature)"}),
},
{
name: "include-quotes",
description: $t({defaultMessage: "Quoted original email (in replies)"}),
},
{
name: "prefer-html",
description: $t({
defaultMessage: "Use html encoding (not recommended)",
}),
},
],
});
dialog_widget.launch({
html_heading: $t_html({defaultMessage: "Generate stream email address"}),
html_body: copy_email_address,
id: "copy_email_address_modal",
html_submit_button: $t_html({defaultMessage: "Copy address"}),
help_link: "/help/message-a-stream-by-email#configuration-options",
on_click() {},
close_on_submit: true,
});
$("#show-sender").prop("checked", true);
new ClipboardJS("#copy_email_address_modal .dialog_submit_button", {
text() {
return address;
channel.get({
url: "/json/streams/" + stream_id + "/email_address",
success(data) {
const address = data.email;
show_stream_email_address_modal(address);
},
error(xhr) {
ui_report.error(
$t_html({defaultMessage: "Failed"}),
xhr,
$(".stream_email_address_error"),
);
},
});
$("#copy_email_address_modal .tag-checkbox").on("change", () => {
const $checked_checkboxes = $(".copy-email-modal").find("input:checked");
const flags = [];
$($checked_checkboxes).each(function () {
flags.push($(this).attr("id"));
});
address = get_stream_email_address(flags, address);
$(".email-address").text(address);
});
});

View File

@@ -943,8 +943,15 @@ h4.user_group_setting_subsection_title {
}
}
.copy_email_button {
padding: 10px 15px;
.stream-email-box {
.stream_email_address_error {
vertical-align: top;
margin-left: 15px;
}
.copy_email_button {
padding: 10px 15px;
}
}
.loading_indicator_text {

View File

@@ -64,11 +64,14 @@
can_remove_subscribers_setting_widget_name="can_remove_subscribers_group_id" }}
</div>
{{/with}}
<div class="stream-email-box" {{#unless sub.email_address}}style="display: none;"{{/unless}}>
<h3 class="stream_setting_subsection_title">
{{t "Email address" }}
{{> ../help_link_widget link="/help/message-a-stream-by-email" }}
</h3>
<div class="stream-email-box" {{#unless can_access_stream_email}}style="display: none;"{{/unless}}>
<div class="stream-email-box-header">
<h3 class="stream_setting_subsection_title">
{{t "Email address" }}
{{> ../help_link_widget link="/help/message-a-stream-by-email" }}
</h3>
<div class="stream_email_address_error alert-notification"></div>
</div>
<p>
{{t "You can use email to send messages to Zulip streams."}}
</p>

View File

@@ -981,3 +981,44 @@ test("can_unsubscribe_others", () => {
page_params.is_admin = false;
assert.equal(stream_data.can_unsubscribe_others(sub), false);
});
test("can_access_stream_email", () => {
const social = {
subscribed: true,
color: "red",
name: "social",
stream_id: 2,
is_muted: false,
invite_only: true,
history_public_to_subscribers: false,
};
page_params.is_admin = false;
assert.equal(stream_data.can_access_stream_email(social), true);
page_params.is_admin = true;
assert.equal(stream_data.can_access_stream_email(social), true);
social.subscribed = false;
assert.equal(stream_data.can_access_stream_email(social), false);
social.invite_only = false;
assert.equal(stream_data.can_access_stream_email(social), true);
page_params.is_admin = false;
assert.equal(stream_data.can_access_stream_email(social), true);
page_params.is_guest = true;
assert.equal(stream_data.can_access_stream_email(social), false);
social.subscribed = true;
assert.equal(stream_data.can_access_stream_email(social), true);
social.is_web_public = true;
assert.equal(stream_data.can_access_stream_email(social), true);
social.subscribed = false;
assert.equal(stream_data.can_access_stream_email(social), true);
page_params.is_spectator = true;
assert.equal(stream_data.can_access_stream_email(social), false);
});