settings: Use user-level email_address_visibility setting in UI.

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.
This commit is contained in:
Sahil Batra
2021-10-26 19:13:39 +05:30
committed by Tim Abbott
parent 0ed5f76063
commit b84885184e
28 changed files with 89 additions and 149 deletions

View File

@@ -5,7 +5,7 @@ const {strict: assert} = require("assert");
const {mock_esm, set_global, with_overrides, zrequire} = require("../zjsunit/namespace");
const {run_test} = require("../zjsunit/test");
const $ = require("../zjsunit/zjquery");
const {page_params, user_settings} = require("../zjsunit/zpage_params");
const {user_settings} = require("../zjsunit/zpage_params");
const noop = () => {};
@@ -861,12 +861,10 @@ test("initialize", ({override, mock_template}) => {
assert.equal(matcher(query, cordelia), false);
query = "oth";
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.admins_only.code;
page_params.is_admin = false;
deactivated_user.delivery_email = null;
assert.equal(matcher(query, deactivated_user), false);
page_params.is_admin = true;
deactivated_user.delivery_email = "other@zulip.com";
assert.equal(matcher(query, deactivated_user), true);
function sorter(query, people) {
@@ -965,6 +963,7 @@ test("initialize", ({override, mock_template}) => {
assert.deepEqual(sorted_names_from(actual_value), ["Sweden", "The Netherlands"]);
assert.ok(caret_called);
othello.delivery_email = "othello@zulip.com";
// options.highlighter()
//
// Again, here we only verify that the highlighter has been set to
@@ -977,6 +976,8 @@ test("initialize", ({override, mock_template}) => {
`<strong>Othello, the Moor of Venice</strong>&nbsp;&nbsp;\n` +
`<small class="autocomplete_secondary">othello@zulip.com</small>\n`;
assert.equal(actual_value, expected_value);
// Reset the email such that this does not affect further tests.
othello.delivery_email = null;
fake_this = {completing: "mention", token: "hamletcharacters"};
actual_value = options.highlighter.call(fake_this, hamletcharacters);

View File

@@ -19,7 +19,6 @@ const people = zrequire("people");
const settings_config = zrequire("settings_config");
const visibility = settings_config.email_address_visibility_values;
const admins_only = visibility.admins_only.code;
const everyone = visibility.everyone.code;
function set_email_visibility(code) {
page_params.realm_email_address_visibility = code;
@@ -1168,26 +1167,33 @@ test_people("matches_user_settings_search", () => {
page_params.is_admin = true;
assert.equal(match({delivery_email: "fred@example.com"}, "fr"), true);
assert.equal(match({delivery_email: "bogus", email: "fred@example.com"}, "fr"), false);
assert.equal(
match(
{
delivery_email: "bogus",
email: "fred@example.com",
},
"fr",
),
false,
);
set_email_visibility(everyone);
page_params.is_admin = false;
assert.equal(match({delivery_email: "fred@example.com"}, "fr"), false);
assert.equal(match({email: "fred@example.com"}, "fr"), true);
assert.equal(match({delivery_email: "fred@example.com"}, "fr"), true);
assert.equal(match({email: "fred@example.com"}, "fr"), false);
// test normal stuff
assert.equal(match({email: "fred@example.com"}, "st"), false);
assert.equal(match({full_name: "Fred Smith"}, "st"), false);
assert.equal(match({full_name: "Joe Frederick"}, "st"), false);
assert.equal(match({email: "fred@example.com"}, "fr"), true);
assert.equal(match({delivery_email: "fred@example.com"}, "fr"), true);
assert.equal(match({full_name: "Fred Smith"}, "fr"), true);
assert.equal(match({full_name: "Joe Frederick"}, "fr"), true);
// test in-string matches...we may want not to be so liberal
// here about matching, as it's noisy for large realms (who
// need search the most)
assert.equal(match({email: "fred@example.com"}, "re"), true);
assert.equal(match({delivery_email: "fred@example.com"}, "re"), true);
assert.equal(match({full_name: "Fred Smith"}, "re"), true);
assert.equal(match({full_name: "Joe Frederick"}, "re"), true);
});

View File

@@ -44,6 +44,7 @@ const popovers = zrequire("popovers");
const alice = {
email: "alice@example.com",
delivery_email: "alice-delivery@example.com",
full_name: "Alice Smith",
user_id: 42,
avatar_version: 5,
@@ -172,7 +173,7 @@ test_ui("sender_hover", ({override, mock_template}) => {
can_send_private_message: true,
display_profile_fields: [],
user_full_name: "Alice Smith",
user_email: "alice@example.com",
user_email: "alice-delivery@example.com",
user_id: 42,
user_time: undefined,
user_type: $t({defaultMessage: "Member"}),
@@ -182,7 +183,6 @@ test_ui("sender_hover", ({override, mock_template}) => {
pm_with_url: "#narrow/pm-with/42-Alice-Smith",
sent_by_uri: "#narrow/sender/42-Alice-Smith",
private_message_class: "respond_personal_button",
show_email: false,
show_manage_menu: true,
is_me: false,
is_active: true,

View File

@@ -34,6 +34,7 @@ const bob = {
const ted = {
email: "ted@zulip.com",
delivery_email: "ted@zulip.com",
user_id: 101,
full_name: "Ted Smith",
};

View File

@@ -34,6 +34,7 @@ const bob = {
const ted = {
email: "ted@zulip.com",
delivery_email: "ted@zulip.com",
user_id: 101,
full_name: "Ted Smith",
};

View File

@@ -23,39 +23,6 @@ const isaac = {
full_name: "Isaac",
};
run_test("email_for_user_settings", () => {
const email = settings_data.email_for_user_settings;
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.admins_only.code;
assert.equal(email(isaac), undefined);
page_params.is_admin = true;
assert.equal(email(isaac), isaac.delivery_email);
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.nobody.code;
assert.equal(email(isaac), undefined);
page_params.is_admin = false;
assert.equal(email(isaac), undefined);
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.everyone.code;
assert.equal(email(isaac), isaac.email);
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.moderators.code;
assert.equal(email(isaac), undefined);
page_params.is_moderator = true;
assert.equal(email(isaac), isaac.delivery_email);
page_params.is_moderator = false;
page_params.is_admin = true;
assert.equal(email(isaac), isaac.delivery_email);
});
run_test("user_can_change_email", () => {
const can_change_email = settings_data.user_can_change_email;

View File

@@ -30,7 +30,6 @@ const user_groups = mock_esm("../../static/js/user_groups", {
const ui_report = mock_esm("../../static/js/ui_report");
const people = zrequire("people");
const settings_config = zrequire("settings_config");
const settings_data = zrequire("settings_data");
const settings_user_groups_legacy = zrequire("settings_user_groups_legacy");
const user_pill = zrequire("user_pill");
@@ -208,13 +207,11 @@ test_ui("populate_user_groups", ({mock_template}) => {
result = config.matcher.call(fake_context, alice);
assert.ok(result);
page_params.realm_email_address_visibility =
settings_config.email_address_visibility_values.admins_only.code;
page_params.is_admin = false;
bob.delivery_email = null;
result = config.matcher.call(fake_context_for_email, bob);
assert.ok(!result);
page_params.is_admin = true;
bob.delivery_email = "bob-delivery@example.com";
result = config.matcher.call(fake_context_for_email, bob);
assert.ok(result);
})();

View File

@@ -678,11 +678,11 @@ test("render_person when emails hidden", ({mock_template}) => {
test("render_person", ({mock_template}) => {
// Test render_person with regular person
page_params.is_admin = true;
a_user.delivery_email = "a_user_delivery@zulip.org";
let rendered = false;
mock_template("typeahead_list_item.hbs", false, (args) => {
assert.equal(args.primary, a_user.full_name);
assert.equal(args.secondary, a_user.email);
assert.equal(args.secondary, a_user.delivery_email);
rendered = true;
return "typeahead-item-stub";
});

View File

@@ -72,6 +72,7 @@ run_test("updates", () => {
const isaac = {
email: "isaac@example.com",
delivery_email: null,
user_id: 32,
full_name: "Isaac Newton",
};
@@ -186,6 +187,19 @@ run_test("updates", () => {
assert.equal(user_id, isaac.user_id);
assert.equal(full_name, "Sir Isaac");
person = people.get_by_email(isaac.email);
assert.equal(person.delivery_email, null);
user_events.update_person({
user_id: isaac.user_id,
delivery_email: "isaac-delivery@example.com",
});
person = people.get_by_email(isaac.email);
assert.equal(person.delivery_email, "isaac-delivery@example.com");
user_events.update_person({user_id: isaac.user_id, delivery_email: null});
person = people.get_by_email(isaac.email);
assert.equal(person.delivery_email, null);
user_events.update_person({user_id: isaac.user_id, avatar_url: "http://gravatar.com/123456"});
person = people.get_by_email(isaac.email);
assert.equal(person.full_name, "Sir Isaac");

View File

@@ -16,6 +16,7 @@ import * as settings_org from "./settings_org";
import * as settings_panel_menu from "./settings_panel_menu";
import * as settings_sections from "./settings_sections";
import * as settings_toggle from "./settings_toggle";
import * as settings_users from "./settings_users";
const admin_settings_label = {
// Organization profile
@@ -186,7 +187,6 @@ export function build_page() {
disable_enable_spectator_access_setting:
!page_params.server_web_public_streams_enabled ||
!page_params.zulip_plan_is_not_limited,
can_sort_by_email: settings_data.show_email(),
realm_push_notifications_enabled: page_params.realm_push_notifications_enabled,
realm_org_type_values: settings_org.get_org_type_dropdown_options(),
realm_want_advertise_in_communities_directory:
@@ -196,6 +196,8 @@ export function build_page() {
is_business_type_org:
page_params.realm_org_type === settings_config.all_org_type_values.business.code,
realm_enable_read_receipts: page_params.realm_enable_read_receipts,
allow_sorting_deactivated_users_list_by_email:
settings_users.allow_sorting_deactivated_users_list_by_email(),
};
if (options.realm_logo_source !== "D" && options.realm_night_logo_source === "D") {

View File

@@ -18,7 +18,6 @@ import * as muted_users from "./muted_users";
import {page_params} from "./page_params";
import * as people from "./people";
import * as rows from "./rows";
import * as settings_data from "./settings_data";
import * as stream_data from "./stream_data";
import * as stream_topic_history from "./stream_topic_history";
import * as stream_topic_history_util from "./stream_topic_history_util";
@@ -90,7 +89,7 @@ function get_language_matcher(query) {
export function query_matches_person(query, person) {
return (
typeahead.query_matches_string(query, person.full_name, " ") ||
(settings_data.show_email() &&
(Boolean(person.delivery_email) &&
typeahead.query_matches_string(query, people.get_visible_email(person), " "))
);
}

View File

@@ -1301,7 +1301,7 @@ function safe_lower(s) {
}
export function matches_user_settings_search(person, value) {
const email = settings_data.email_for_user_settings(person);
const email = person.delivery_email;
return safe_lower(person.full_name).includes(value) || safe_lower(email).includes(value);
}

View File

@@ -37,7 +37,6 @@ import * as resize from "./resize";
import * as rows from "./rows";
import * as settings_bots from "./settings_bots";
import * as settings_config from "./settings_config";
import * as settings_data from "./settings_data";
import * as settings_users from "./settings_users";
import * as stream_popover from "./stream_popover";
import * as ui_report from "./ui_report";
@@ -275,9 +274,8 @@ function render_user_info_popover(
user_circle_class: buddy_data.get_user_circle_class(user.user_id),
private_message_class: private_msg_class,
sent_by_uri: hash_util.by_sender_url(user.email),
show_email: settings_data.show_email(),
show_manage_menu,
user_email: people.get_visible_email(user),
user_email: user.delivery_email,
user_full_name: user.full_name,
user_id: user.user_id,
user_last_seen_time_status: buddy_data.user_last_seen_time_status(user.user_id),

View File

@@ -18,60 +18,6 @@ export function initialize(current_user_join_date: Date): void {
about page_params and settings_config details.
*/
function user_can_access_delivery_email(): boolean {
// This function checks whether the current user should expect to
// see .delivery_email fields on user objects that it can access.
//
// If false, either everyone has access to emails (and there is no
// delivery_email field for anyone) or this user does not have
// access to emails (and this client will never receive a user
// object with a delivery_email field).
if (
page_params.realm_email_address_visibility ===
settings_config.email_address_visibility_values.admins_only.code
) {
return page_params.is_admin;
}
if (
page_params.realm_email_address_visibility ===
settings_config.email_address_visibility_values.moderators.code
) {
return page_params.is_admin || page_params.is_moderator;
}
return false;
}
export function show_email(): boolean {
if (
page_params.realm_email_address_visibility ===
settings_config.email_address_visibility_values.everyone.code
) {
return true;
}
return user_can_access_delivery_email();
}
// TODO: Move this to people when converting it
// to TypeScript.
interface Person {
delivery_email: string;
email: string;
}
export function email_for_user_settings(person: Person): string | undefined {
if (!show_email()) {
return undefined;
}
if (person.delivery_email && user_can_access_delivery_email()) {
return person.delivery_email;
}
return person.email;
}
export function get_time_preferences(user_timezone: string): {
timezone: string;
format: string;

View File

@@ -20,7 +20,6 @@ import * as presence from "./presence";
import * as settings_account from "./settings_account";
import * as settings_bots from "./settings_bots";
import * as settings_config from "./settings_config";
import * as settings_data from "./settings_data";
import * as settings_panel_menu from "./settings_panel_menu";
import * as timerender from "./timerender";
import * as ui from "./ui";
@@ -42,8 +41,22 @@ function compare_a_b(a, b) {
}
function sort_email(a, b) {
const email_a = settings_data.email_for_user_settings(a) || "";
const email_b = settings_data.email_for_user_settings(b) || "";
const email_a = a.delivery_email;
const email_b = b.delivery_email;
if (email_a === null && email_b === null) {
// If both the emails are hidden, we sort the list by name.
return compare_a_b(a.full_name.toLowerCase(), b.full_name.toLowerCase());
}
if (email_a === null) {
// User with hidden should be at last.
return 1;
}
if (email_b === null) {
// User with hidden should be at last.
return -1;
}
return compare_a_b(email_a.toLowerCase(), email_b.toLowerCase());
}
@@ -82,6 +95,15 @@ function get_user_info_row(user_id) {
return $(`tr.user_row[data-user-id='${CSS.escape(user_id)}']`);
}
export function allow_sorting_deactivated_users_list_by_email() {
const deactivated_users = people.get_non_active_realm_users();
const deactivated_humans_with_visble_email = deactivated_users.filter(
(user) => !user.is_bot && user.delivery_email,
);
return deactivated_humans_with_visble_email.length !== 0;
}
export function update_view_on_deactivate(user_id) {
const $row = get_user_info_row(user_id);
if ($row.length === 0) {
@@ -236,7 +258,7 @@ function human_info(person) {
info.can_modify = page_params.is_admin;
info.is_current_user = people.is_my_user_id(person.user_id);
info.cannot_deactivate = info.is_current_user || (person.is_owner && !page_params.is_owner);
info.display_email = settings_data.email_for_user_settings(person);
info.display_email = person.delivery_email;
if (info.is_active) {
// TODO: We might just want to show this
@@ -451,7 +473,7 @@ export function confirm_deactivation(user_id, handle_confirm, loading_spinner) {
const realm_name = page_params.realm_name;
const opts = {
username: user.full_name,
email: settings_data.email_for_user_settings(user),
email: user.delivery_email,
bots_owned_by_user,
number_of_invites_by_user,
admin_email: people.my_current_email(),
@@ -574,11 +596,9 @@ export function show_edit_user_info_modal(user_id, from_user_info_popover) {
return;
}
const user_email = settings_data.email_for_user_settings(person);
const html_body = render_admin_human_form({
user_id,
email: user_email,
email: person.delivery_email,
full_name: person.full_name,
user_role_values: settings_config.user_role_values,
disable_role_dropdown: person.is_owner && !page_params.is_owner,

View File

@@ -7,7 +7,6 @@ import * as add_subscribers_pill from "./add_subscribers_pill";
import * as ListWidget from "./list_widget";
import {page_params} from "./page_params";
import * as people from "./people";
import * as settings_data from "./settings_data";
import * as stream_create_subscribers_data from "./stream_create_subscribers_data";
let pill_widget;
@@ -88,8 +87,7 @@ export function build_widgets() {
modifier(user_id) {
const user = people.get_by_user_id(user_id);
const item = {
show_email: settings_data.show_email(),
email: people.get_visible_email(user),
email: user.delivery_email,
user_id,
full_name: user.full_name,
is_current_user: user_id === current_user_id,

View File

@@ -14,7 +14,6 @@ import * as ListWidget from "./list_widget";
import {page_params} from "./page_params";
import * as peer_data from "./peer_data";
import * as people from "./people";
import * as settings_data from "./settings_data";
import * as stream_data from "./stream_data";
import * as stream_settings_containers from "./stream_settings_containers";
import * as sub_store from "./sub_store";
@@ -30,9 +29,8 @@ function format_member_list_elem(person, user_can_remove_subscribers) {
name: person.full_name,
user_id: person.user_id,
is_current_user: person.user_id === page_params.user_id,
email: settings_data.email_for_user_settings(person),
email: person.delivery_email,
can_remove_subscribers: user_can_remove_subscribers,
show_email: settings_data.show_email(),
});
}

View File

@@ -10,7 +10,6 @@ import * as compose_state from "./compose_state";
import * as people from "./people";
import * as pm_conversations from "./pm_conversations";
import * as recent_senders from "./recent_senders";
import * as settings_data from "./settings_data";
import * as stream_data from "./stream_data";
import * as user_groups from "./user_groups";
import * as user_status from "./user_status";
@@ -95,7 +94,7 @@ export function render_person(person) {
status_emoji_info,
};
typeahead_arguments.secondary = settings_data.email_for_user_settings(person);
typeahead_arguments.secondary = person.delivery_email;
return render_typeahead_item(typeahead_arguments);
}

View File

@@ -45,7 +45,7 @@ export const update_person = function update(person) {
if (Object.hasOwn(person, "delivery_email")) {
const delivery_email = person.delivery_email;
person_obj.delivery_email = delivery_email;
if (people.is_my_user_id(person.user_id)) {
settings_account.update_email(delivery_email);
page_params.delivery_email = delivery_email;

View File

@@ -7,7 +7,6 @@ import * as add_subscribers_pill from "./add_subscribers_pill";
import * as ListWidget from "./list_widget";
import {page_params} from "./page_params";
import * as people from "./people";
import * as settings_data from "./settings_data";
import * as user_group_create_members_data from "./user_group_create_members_data";
let pill_widget;
@@ -96,8 +95,7 @@ export function build_widgets() {
modifier(user_id) {
const user = people.get_by_user_id(user_id);
const item = {
show_email: settings_data.show_email(),
email: people.get_visible_email(user),
email: user.delivery_email,
user_id,
full_name: user.full_name,
is_current_user: user_id === current_user_id,

View File

@@ -13,7 +13,6 @@ import {$t, $t_html} from "./i18n";
import * as ListWidget from "./list_widget";
import {page_params} from "./page_params";
import * as people from "./people";
import * as settings_data from "./settings_data";
import * as ui from "./ui";
import * as user_group_edit from "./user_group_edit";
import * as user_groups from "./user_groups";
@@ -50,9 +49,8 @@ function format_member_list_elem(person) {
name: person.full_name,
user_id: person.user_id,
is_current_user: person.user_id === page_params.user_id,
email: settings_data.email_for_user_settings(person),
email: person.delivery_email,
can_edit_subscribers: user_group_edit.can_edit(current_group_id),
show_email: settings_data.show_email(),
});
}

View File

@@ -18,7 +18,6 @@ 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_data from "./settings_data";
import * as settings_profile_fields from "./settings_profile_fields";
import * as stream_data from "./stream_data";
import * as sub_store from "./sub_store";
@@ -190,7 +189,7 @@ export function show_user_profile(user, default_tab_key = "profile-tab") {
const args = {
user_id: user.user_id,
full_name: user.full_name,
email: people.get_visible_email(user),
email: user.delivery_email,
profile_data,
user_avatar: people.medium_avatar_url_for_person(user),
is_me: people.is_current_user(user.email),
@@ -198,7 +197,6 @@ export function show_user_profile(user, default_tab_key = "profile-tab") {
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),
show_email: settings_data.show_email(),
user_time: people.get_user_time(user.user_id),
user_type: people.get_user_type(user.user_id),
user_is_guest: user.is_guest,
@@ -212,7 +210,6 @@ export function show_user_profile(user, default_tab_key = "profile-tab") {
} else if (bot_owner_id) {
const bot_owner = people.get_by_user_id(bot_owner_id);
args.bot_owner = bot_owner;
args.show_email = true;
}
args.bot_type = settings_bots.type_id_to_string(user.bot_type);
}

View File

@@ -13,7 +13,7 @@
<table class="table table-condensed table-striped wrapped-table">
<thead class="table-sticky-headers">
<th class="active" data-sort="alphabetic" data-sort-prop="full_name">{{t "Name" }}</th>
<th {{#if can_sort_by_email}}data-sort="email"{{/if}}>{{t "Email" }}</th>
<th {{#if allow_sorting_deactivated_users_list_by_email}}data-sort="email"{{/if}}>{{t "Email" }}</th>
<th class="user_id" data-sort="id">{{t "User ID" }}</th>
<th class="user_role" data-sort="role">{{t "Role" }}</th>
{{#if is_admin}}

View File

@@ -12,7 +12,7 @@
<table class="table table-condensed table-striped wrapped-table">
<thead class="table-sticky-headers">
<th class="active" data-sort="alphabetic" data-sort-prop="full_name">{{t "Name" }}</th>
<th {{#if can_sort_by_email}}data-sort="email"{{/if}}>{{t "Email" }}</th>
<th data-sort="email">{{t "Email" }}</th>
<th class="user_id" data-sort="id">{{t "User ID" }}</th>
<th class="user_role" data-sort="role">{{t "Role" }}</th>
<th class="last_active" data-sort="last_active">{{t "Last active" }}</th>

View File

@@ -2,7 +2,7 @@
<td>
{{full_name}}{{#if is_current_user}} <span class="my_user_status">{{t "(you)"}}</span>{{/if}}
</td>
{{#if show_email}}
{{#if email}}
<td class="subscriber-email">{{email}}</td>
{{else}}
<td class="hidden-subscriber-email">{{t "(hidden)"}}</td>

View File

@@ -3,7 +3,7 @@
<a data-user-id="{{user_id}}" class="view_user_profile" tabindex="0">{{name}}</a>
{{#if is_current_user}} <span class="my_user_status">{{t "(you)"}}</span>{{/if}}
</td>
{{#if show_email}}
{{#if email}}
<td class="subscriber-email">{{email}}</td>
{{else}}
<td class="hidden-subscriber-email">{{t "(hidden)"}}</td>

View File

@@ -20,7 +20,7 @@
{{#if is_active }}
{{#if show_email}}
{{#if user_email}}
{{!-- This div is added to enable interactivity for tooltip - https://atomiks.github.io/tippyjs/v5/accessibility/#interactivity --}}
<div>
<li class="user_popover_email">

View File

@@ -25,7 +25,7 @@
<div class="top">
<div class="col-wrap col-left">
<div id="default-section">
{{#if show_email}}
{{#if email}}
<div id="email" class="default-field">
<div class="name">{{#tr}}Email{{/tr}}</div>
<div class="value">{{email}}</div>