mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 22:43:42 +00:00
This commit basically updates the frontend code to directly use delivery_email field instead of functions like show_email or email_for_user_settings at places where we want to show email. We can do this change since we recently updated the server code to always pass "delivery_email" code in the user objects with its value being null if the real email is not accessible. Showing email or "hidden" or nothing at various places in UI like in users list, subscriber list, user profile popover and modal is same as before. Major points - - Removed show_email and email_for_user_settings functions since we directly use delivery_email field now as explained above. - While sorting by emails in the users list, users with real emails hidden are always shown in last when sorting alphabetically and at the top when sorting reverse alphabetically. Also, those users with real emails hidden, are sorted by name among themselves. As we did before, we do not allow sorting by email when all emails are hidden. - There is no change in typeahead behavior at this point. We either hide the email completely or show the real or fake email based on user level setting. - Added code to handle delivery_email events and appropriately add/remove delivery_email field from person objects.
374 lines
14 KiB
JavaScript
374 lines
14 KiB
JavaScript
import {parseISO} from "date-fns";
|
|
import $ from "jquery";
|
|
|
|
import render_user_group_list_item from "../templates/user_group_list_item.hbs";
|
|
import render_user_profile_modal from "../templates/user_profile_modal.hbs";
|
|
import render_user_stream_list_item from "../templates/user_stream_list_item.hbs";
|
|
|
|
import * as browser_history from "./browser_history";
|
|
import * as buddy_data from "./buddy_data";
|
|
import * as channel from "./channel";
|
|
import * as components from "./components";
|
|
import * as hash_util from "./hash_util";
|
|
import {$t, $t_html} from "./i18n";
|
|
import * as ListWidget from "./list_widget";
|
|
import * as overlays from "./overlays";
|
|
import {page_params} from "./page_params";
|
|
import * as people from "./people";
|
|
import * as popovers from "./popovers";
|
|
import * as settings_account from "./settings_account";
|
|
import * as settings_bots from "./settings_bots";
|
|
import * as settings_profile_fields from "./settings_profile_fields";
|
|
import * as stream_data from "./stream_data";
|
|
import * as sub_store from "./sub_store";
|
|
import * as subscriber_api from "./subscriber_api";
|
|
import * as ui_report from "./ui_report";
|
|
import * as user_groups from "./user_groups";
|
|
import * as user_pill from "./user_pill";
|
|
import * as util from "./util";
|
|
|
|
function compare_by_name(a, b) {
|
|
return util.strcmp(a.name, b.name);
|
|
}
|
|
|
|
function initialize_bot_owner(element_id, bot_id) {
|
|
const user_pills = new Map();
|
|
const bot = people.get_by_user_id(bot_id);
|
|
const bot_owner = people.get_bot_owner_user(bot);
|
|
// Bot owner's pill displaying on bot's profile modal.
|
|
if (bot_owner) {
|
|
const $pill_container = $(element_id)
|
|
.find(
|
|
`.bot_owner_user_field[data-field-id="${CSS.escape(
|
|
bot_owner.user_id,
|
|
)}"] .pill-container`,
|
|
)
|
|
.expectOne();
|
|
const pills = user_pill.create_pills($pill_container);
|
|
|
|
user_pill.append_user(bot_owner, pills);
|
|
user_pills.set(bot_owner.user_id, pills);
|
|
}
|
|
return user_pills;
|
|
}
|
|
|
|
function format_user_stream_list_item(stream, user) {
|
|
const show_unsubscribe_button =
|
|
people.can_admin_user(user) || stream_data.can_unsubscribe_others(stream);
|
|
const show_private_stream_unsub_tooltip =
|
|
people.is_my_user_id(user.user_id) && stream.invite_only;
|
|
return render_user_stream_list_item({
|
|
name: stream.name,
|
|
stream_id: stream.stream_id,
|
|
stream_color: stream.color,
|
|
invite_only: stream.invite_only,
|
|
is_web_public: stream.is_web_public,
|
|
show_unsubscribe_button,
|
|
show_private_stream_unsub_tooltip,
|
|
stream_edit_url: hash_util.stream_edit_url(stream),
|
|
});
|
|
}
|
|
|
|
function format_user_group_list_item(group) {
|
|
return render_user_group_list_item({
|
|
group_id: group.id,
|
|
name: group.name,
|
|
});
|
|
}
|
|
|
|
function render_user_stream_list(streams, user) {
|
|
streams.sort(compare_by_name);
|
|
const $container = $("#user-profile-modal .user-stream-list");
|
|
$container.empty();
|
|
ListWidget.create($container, streams, {
|
|
name: `user-${user.user_id}-stream-list`,
|
|
modifier(item) {
|
|
return format_user_stream_list_item(item, user);
|
|
},
|
|
filter: {
|
|
$element: $("#user-profile-streams-tab .stream-search"),
|
|
predicate(item, value) {
|
|
return item && item.name.toLocaleLowerCase().includes(value);
|
|
},
|
|
},
|
|
$simplebar_container: $("#user-profile-modal .modal__body"),
|
|
});
|
|
}
|
|
|
|
function render_user_group_list(groups, user) {
|
|
groups.sort(compare_by_name);
|
|
const $container = $("#user-profile-modal .user-group-list");
|
|
$container.empty();
|
|
ListWidget.create($container, groups, {
|
|
name: `user-${user.user_id}-group-list`,
|
|
modifier(item) {
|
|
return format_user_group_list_item(item);
|
|
},
|
|
$simplebar_container: $("#user-profile-modal .modal__body"),
|
|
});
|
|
}
|
|
|
|
export function get_custom_profile_field_data(user, field, field_types, dateFormat) {
|
|
const field_value = people.get_custom_profile_data(user.user_id, field.id);
|
|
const field_type = field.type;
|
|
const profile_field = {};
|
|
|
|
if (!field_value) {
|
|
return profile_field;
|
|
}
|
|
if (!field_value.value) {
|
|
return profile_field;
|
|
}
|
|
profile_field.name = field.name;
|
|
profile_field.is_user_field = false;
|
|
profile_field.is_link = field_type === field_types.URL.id;
|
|
profile_field.is_external_account = field_type === field_types.EXTERNAL_ACCOUNT.id;
|
|
profile_field.type = field_type;
|
|
profile_field.display_in_profile_summary = field.display_in_profile_summary;
|
|
|
|
switch (field_type) {
|
|
case field_types.DATE.id:
|
|
profile_field.value = dateFormat.format(parseISO(field_value.value));
|
|
break;
|
|
case field_types.USER.id:
|
|
profile_field.id = field.id;
|
|
profile_field.is_user_field = true;
|
|
profile_field.value = field_value.value;
|
|
break;
|
|
case field_types.SELECT.id: {
|
|
const field_choice_dict = JSON.parse(field.field_data);
|
|
profile_field.value = field_choice_dict[field_value.value].text;
|
|
break;
|
|
}
|
|
case field_types.SHORT_TEXT.id:
|
|
case field_types.LONG_TEXT.id:
|
|
profile_field.value = field_value.value;
|
|
profile_field.rendered_value = field_value.rendered_value;
|
|
break;
|
|
case field_types.EXTERNAL_ACCOUNT.id:
|
|
profile_field.value = field_value.value;
|
|
profile_field.field_data = JSON.parse(field.field_data);
|
|
profile_field.subtype = profile_field.field_data.subtype;
|
|
profile_field.link = settings_profile_fields.get_external_account_link(profile_field);
|
|
break;
|
|
default:
|
|
profile_field.value = field_value.value;
|
|
}
|
|
return profile_field;
|
|
}
|
|
|
|
export function hide_user_profile() {
|
|
overlays.close_modal("user-profile-modal");
|
|
}
|
|
|
|
function initialize_user_type_fields(user) {
|
|
// Avoid duplicate pill fields, by removing existing ones.
|
|
$("#user-profile-modal .pill").remove();
|
|
if (!user.is_bot) {
|
|
settings_account.initialize_custom_user_type_fields(
|
|
"#user-profile-modal #content",
|
|
user.user_id,
|
|
false,
|
|
false,
|
|
);
|
|
} else {
|
|
initialize_bot_owner("#user-profile-modal #content", user.user_id);
|
|
}
|
|
}
|
|
|
|
export function show_user_profile(user, default_tab_key = "profile-tab") {
|
|
popovers.hide_all();
|
|
|
|
const dateFormat = new Intl.DateTimeFormat("default", {dateStyle: "long"});
|
|
const field_types = page_params.custom_profile_field_types;
|
|
const profile_data = page_params.custom_profile_fields
|
|
.map((f) => get_custom_profile_field_data(user, f, field_types, dateFormat))
|
|
.filter((f) => f.name !== undefined);
|
|
const user_streams = stream_data.get_subscribed_streams_for_user(user.user_id);
|
|
const groups_of_user = user_groups.get_user_groups_of_user(user.user_id);
|
|
const args = {
|
|
user_id: user.user_id,
|
|
full_name: user.full_name,
|
|
email: user.delivery_email,
|
|
profile_data,
|
|
user_avatar: people.medium_avatar_url_for_person(user),
|
|
is_me: people.is_current_user(user.email),
|
|
is_bot: user.is_bot,
|
|
date_joined: dateFormat.format(parseISO(user.date_joined)),
|
|
user_circle_class: buddy_data.get_user_circle_class(user.user_id),
|
|
last_seen: buddy_data.user_last_seen_time_status(user.user_id),
|
|
user_time: people.get_user_time(user.user_id),
|
|
user_type: people.get_user_type(user.user_id),
|
|
user_is_guest: user.is_guest,
|
|
};
|
|
|
|
if (user.is_bot) {
|
|
const is_system_bot = user.is_system_bot;
|
|
const bot_owner_id = user.bot_owner_id;
|
|
if (is_system_bot) {
|
|
args.is_system_bot = is_system_bot;
|
|
} else if (bot_owner_id) {
|
|
const bot_owner = people.get_by_user_id(bot_owner_id);
|
|
args.bot_owner = bot_owner;
|
|
}
|
|
args.bot_type = settings_bots.type_id_to_string(user.bot_type);
|
|
}
|
|
|
|
$("#user-profile-modal-holder").html(render_user_profile_modal(args));
|
|
overlays.open_modal("user-profile-modal", {autoremove: true});
|
|
$(".tabcontent").hide();
|
|
|
|
let default_tab = 0;
|
|
// Only checking this tab key as currently we only open this tab directly
|
|
// other than profile-tab.
|
|
if (default_tab_key === "user-profile-streams-tab") {
|
|
default_tab = 1;
|
|
}
|
|
|
|
const opts = {
|
|
selected: default_tab,
|
|
child_wants_focus: true,
|
|
values: [
|
|
{label: $t({defaultMessage: "Profile"}), key: "profile-tab"},
|
|
{label: $t({defaultMessage: "Streams"}), key: "user-profile-streams-tab"},
|
|
{label: $t({defaultMessage: "User groups"}), key: "user-profile-groups-tab"},
|
|
],
|
|
callback(name, key) {
|
|
$(".tabcontent").hide();
|
|
$("#" + key).show();
|
|
switch (key) {
|
|
case "profile-tab":
|
|
initialize_user_type_fields(user);
|
|
break;
|
|
case "user-profile-groups-tab":
|
|
render_user_group_list(groups_of_user, user);
|
|
break;
|
|
case "user-profile-streams-tab":
|
|
render_user_stream_list(user_streams, user);
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
|
|
const $elem = components.toggle(opts).get();
|
|
$elem.addClass("large allow-overflow");
|
|
$("#tab-toggle").append($elem);
|
|
}
|
|
|
|
function handle_remove_stream_subscription(target_user_id, sub, success, failure) {
|
|
if (people.is_my_user_id(target_user_id)) {
|
|
// Self unsubscribe.
|
|
channel.del({
|
|
url: "/json/users/me/subscriptions",
|
|
data: {subscriptions: JSON.stringify([sub.name])},
|
|
success,
|
|
error: failure,
|
|
});
|
|
} else {
|
|
subscriber_api.remove_user_id_from_stream(target_user_id, sub, success, failure);
|
|
}
|
|
}
|
|
|
|
export function register_click_handlers() {
|
|
$("body").on("click", ".info_popover_actions .view_full_user_profile", (e) => {
|
|
const user_id = popovers.elem_to_user_id($(e.target).parents("ul"));
|
|
const user = people.get_by_user_id(user_id);
|
|
show_user_profile(user);
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
});
|
|
|
|
$("body").on("click", "#user-profile-modal .remove-subscription-button", (e) => {
|
|
e.preventDefault();
|
|
const $stream_row = $(e.currentTarget).closest("[data-stream-id]");
|
|
const stream_id = Number.parseInt($stream_row.attr("data-stream-id"), 10);
|
|
const sub = sub_store.get(stream_id);
|
|
const target_user_id = Number.parseInt(
|
|
$stream_row.closest("#user-profile-modal").attr("data-user-id"),
|
|
10,
|
|
);
|
|
const $alert_box = $("#user-profile-streams-tab .stream_list_info");
|
|
|
|
function removal_success(data) {
|
|
if (data.removed.length > 0) {
|
|
// Most of the work for handling the unsubscribe is done
|
|
// by the subscription -> remove event we will get.
|
|
// However, the user profile component has not yet
|
|
// implemented live update, so we do update its
|
|
// UI manually here by removing the stream from this list.
|
|
$stream_row.remove();
|
|
|
|
ui_report.success(
|
|
$t_html({defaultMessage: "Unsubscribed successfully!"}),
|
|
$alert_box,
|
|
1200,
|
|
);
|
|
} else {
|
|
ui_report.client_error(
|
|
$t_html({defaultMessage: "Already not subscribed."}),
|
|
$alert_box,
|
|
1200,
|
|
);
|
|
}
|
|
}
|
|
|
|
function removal_failure() {
|
|
let error_message;
|
|
if (people.is_my_user_id(target_user_id)) {
|
|
error_message = $t(
|
|
{defaultMessage: "Error in unsubscribing from #{stream_name}"},
|
|
{stream_name: sub.name},
|
|
);
|
|
} else {
|
|
error_message = $t(
|
|
{defaultMessage: "Error removing user from #{stream_name}"},
|
|
{stream_name: sub.name},
|
|
);
|
|
}
|
|
|
|
ui_report.client_error(error_message, $alert_box, 1200);
|
|
}
|
|
|
|
if (sub.invite_only && people.is_my_user_id(target_user_id)) {
|
|
const new_hash = hash_util.stream_edit_url(sub);
|
|
hide_user_profile();
|
|
browser_history.go_to_location(new_hash);
|
|
return;
|
|
}
|
|
handle_remove_stream_subscription(target_user_id, sub, removal_success, removal_failure);
|
|
});
|
|
|
|
$("body").on("click", "#user-profile-modal #clear_stream_search", (e) => {
|
|
const $input = $("#user-profile-streams-tab .stream-search");
|
|
$input.val("");
|
|
|
|
// This is a hack to rerender complete
|
|
// stream list once the text is cleared.
|
|
$input.trigger("input");
|
|
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
});
|
|
/* These click handlers are implemented as just deep links to the
|
|
* relevant part of the Zulip UI, so we don't want preventDefault,
|
|
* but we do want to close the modal when you click them. */
|
|
$("body").on("click", "#user-profile-modal #name #edit-button", () => {
|
|
hide_user_profile();
|
|
});
|
|
|
|
$("body").on("click", "#user-profile-modal .stream_list_item", () => {
|
|
hide_user_profile();
|
|
});
|
|
|
|
$("body").on("input", "#user-profile-streams-tab .stream-search", () => {
|
|
const $input = $("#user-profile-streams-tab .stream-search");
|
|
if ($input.val().trim().length > 0) {
|
|
$("#user-profile-streams-tab #clear_stream_search").show();
|
|
$input.css("margin-right", "-20px");
|
|
} else {
|
|
$("#user-profile-streams-tab #clear_stream_search").hide();
|
|
$input.css("margin-right", "0");
|
|
}
|
|
});
|
|
}
|