2020-02-25 12:46:14 +01:00
|
|
|
const settings_data = require("./settings_data");
|
2020-05-29 16:12:09 +02:00
|
|
|
const settings_config = require("./settings_config");
|
2019-11-02 00:06:25 +01:00
|
|
|
const render_admin_user_list = require("../templates/admin_user_list.hbs");
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
const render_admin_human_form = require('../templates/admin_human_form.hbs');
|
|
|
|
const render_admin_bot_form = require('../templates/admin_bot_form.hbs');
|
2019-07-09 21:24:00 +02:00
|
|
|
|
2020-05-07 15:43:20 +02:00
|
|
|
const section = {
|
|
|
|
active: {},
|
|
|
|
deactivated: {},
|
|
|
|
bots: {},
|
|
|
|
};
|
|
|
|
|
2019-08-16 06:02:53 +02:00
|
|
|
function compare_a_b(a, b) {
|
|
|
|
if (a > b) {
|
|
|
|
return 1;
|
|
|
|
} else if (a === b) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-04-15 15:09:23 +02:00
|
|
|
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) || '';
|
|
|
|
return compare_a_b(
|
|
|
|
email_a.toLowerCase(),
|
|
|
|
email_b.toLowerCase()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:52:27 +02:00
|
|
|
function sort_bot_email(a, b) {
|
|
|
|
function email(bot) {
|
|
|
|
return (bot.display_email || '').toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
return compare_a_b(email(a), email(b));
|
|
|
|
}
|
|
|
|
|
2020-04-12 12:13:47 +02:00
|
|
|
function sort_role(a, b) {
|
|
|
|
function role(user) {
|
|
|
|
if (user.is_admin) { return 0; }
|
|
|
|
if (user.is_guest) { return 2; }
|
|
|
|
return 1; // member
|
|
|
|
}
|
|
|
|
return compare_a_b(role(a), role(b));
|
|
|
|
}
|
|
|
|
|
|
|
|
function sort_bot_owner(a, b) {
|
2020-05-10 12:52:27 +02:00
|
|
|
function owner_name(bot) {
|
|
|
|
return (bot.bot_owner_full_name || '').toLowerCase();
|
2020-04-15 15:35:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return compare_a_b(
|
|
|
|
owner_name(a),
|
|
|
|
owner_name(b)
|
|
|
|
);
|
2020-04-12 12:13:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function sort_last_active(a, b) {
|
2020-03-25 22:17:45 +01:00
|
|
|
return compare_a_b(
|
2020-06-02 21:07:09 +02:00
|
|
|
presence.last_active_date(a.user_id) || 0,
|
|
|
|
presence.last_active_date(b.user_id) || 0
|
2020-03-25 22:17:45 +01:00
|
|
|
);
|
2020-04-12 12:13:47 +02:00
|
|
|
}
|
|
|
|
|
2018-07-14 12:43:04 +02:00
|
|
|
function get_user_info_row(user_id) {
|
|
|
|
return $("tr.user_row[data-user-id='" + user_id + "']");
|
2017-04-08 20:08:35 +02:00
|
|
|
}
|
|
|
|
|
2020-05-29 16:12:09 +02:00
|
|
|
function set_user_role_dropdown(person) {
|
|
|
|
let role_value = settings_config.user_role_values.member.code;
|
2020-06-03 23:30:34 +02:00
|
|
|
if (person.is_owner) {
|
|
|
|
role_value = settings_config.user_role_values.owner.code;
|
|
|
|
} else if (person.is_admin) {
|
2020-05-29 16:12:09 +02:00
|
|
|
role_value = settings_config.user_role_values.admin.code;
|
|
|
|
} else if (person.is_guest) {
|
|
|
|
role_value = settings_config.user_role_values.guest.code;
|
|
|
|
}
|
|
|
|
$('#user-role-select').val(role_value);
|
|
|
|
}
|
|
|
|
|
2019-03-18 11:07:51 +01:00
|
|
|
function update_view_on_deactivate(row) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const button = row.find("button.deactivate");
|
|
|
|
const user_role = row.find(".user_role");
|
2019-03-18 12:16:06 +01:00
|
|
|
button.prop("disabled", false);
|
2017-04-08 20:08:35 +02:00
|
|
|
row.find('button.open-user-form').hide();
|
2019-05-16 10:36:20 +02:00
|
|
|
row.find('i.deactivated-user-icon').show();
|
|
|
|
button.addClass("btn-warning reactivate");
|
|
|
|
button.removeClass("deactivate btn-danger");
|
2020-04-06 07:15:39 +02:00
|
|
|
button.html("<i class='fa fa-user-plus' aria-hidden='true'></i>");
|
|
|
|
button.attr('title', 'Reactivate');
|
2017-04-08 20:08:35 +02:00
|
|
|
row.addClass("deactivated_user");
|
2019-05-16 10:36:20 +02:00
|
|
|
|
|
|
|
if (user_role) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const user_id = row.data('user-id');
|
2019-05-16 10:36:20 +02:00
|
|
|
user_role.text("%state (%role)".replace("%state", i18n.t("Deactivated")).
|
|
|
|
replace("%role", people.get_user_type(user_id)));
|
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
}
|
2019-03-18 11:04:03 +01:00
|
|
|
|
2019-03-18 12:05:52 +01:00
|
|
|
function update_view_on_reactivate(row) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const button = row.find("button.reactivate");
|
|
|
|
const user_role = row.find(".user_role");
|
2019-03-18 11:04:03 +01:00
|
|
|
row.find("button.open-user-form").show();
|
2019-05-16 10:36:20 +02:00
|
|
|
row.find('i.deactivated-user-icon').hide();
|
|
|
|
button.addClass("btn-danger deactivate");
|
|
|
|
button.removeClass("btn-warning reactivate");
|
2020-04-06 07:15:39 +02:00
|
|
|
button.attr('title', 'Deactivate');
|
|
|
|
button.html('<i class="fa fa-user-plus" aria-hidden="true"></i>');
|
2019-03-18 11:04:03 +01:00
|
|
|
row.removeClass("deactivated_user");
|
2019-05-16 10:36:20 +02:00
|
|
|
|
|
|
|
if (user_role) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const user_id = row.data('user-id');
|
2019-05-16 10:36:20 +02:00
|
|
|
user_role.text(people.get_user_type(user_id));
|
|
|
|
}
|
2019-03-18 11:04:03 +01:00
|
|
|
}
|
|
|
|
|
2019-01-14 14:04:27 +01:00
|
|
|
function get_status_field() {
|
2019-11-02 00:06:25 +01:00
|
|
|
const current_tab = settings_panel_menu.org_settings.current_tab();
|
2019-01-14 14:04:27 +01:00
|
|
|
switch (current_tab) {
|
|
|
|
case 'deactivated-users-admin':
|
|
|
|
return $("#deactivated-user-field-status").expectOne();
|
|
|
|
case 'user-list-admin':
|
|
|
|
return $("#user-field-status").expectOne();
|
|
|
|
case 'bot-list-admin':
|
|
|
|
return $("#bot-field-status").expectOne();
|
|
|
|
default:
|
|
|
|
blueslip.fatal("Invalid admin settings page");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-09 04:14:32 +02:00
|
|
|
function failed_listing_users() {
|
2017-04-08 20:08:35 +02:00
|
|
|
loading.destroy_indicator($('#subs_page_loading_indicator'));
|
2019-11-02 00:06:25 +01:00
|
|
|
const status = get_status_field();
|
2020-06-09 04:14:32 +02:00
|
|
|
const user_id = people.my_current_user_id();
|
|
|
|
blueslip.error('Error while listing users for user_id ' + user_id, status);
|
2017-04-08 20:08:35 +02:00
|
|
|
}
|
|
|
|
|
2020-06-09 04:14:32 +02:00
|
|
|
function populate_users() {
|
|
|
|
const active_user_ids = people.get_active_human_ids();
|
|
|
|
const deactivated_user_ids = people.get_non_active_human_ids();
|
2020-05-09 20:06:14 +02:00
|
|
|
|
2020-06-09 04:14:32 +02:00
|
|
|
if (active_user_ids.length === 0 && deactivated_user_ids.length === 0) {
|
|
|
|
failed_listing_users();
|
2020-01-16 20:12:06 +01:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-06-10 03:02:34 +02:00
|
|
|
section.active.create_table(active_user_ids);
|
|
|
|
section.deactivated.create_table(deactivated_user_ids);
|
2020-05-07 15:43:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function reset_scrollbar($sel) {
|
|
|
|
return function () {
|
|
|
|
ui.reset_scrollbar($sel);
|
2017-09-26 22:16:52 +02:00
|
|
|
};
|
2020-05-07 15:43:20 +02:00
|
|
|
}
|
2017-09-26 22:16:52 +02:00
|
|
|
|
2020-05-11 00:54:00 +02:00
|
|
|
function bot_owner_full_name(owner_id) {
|
|
|
|
if (!owner_id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const bot_owner = people.get_by_user_id(owner_id);
|
|
|
|
if (!bot_owner) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bot_owner.full_name;
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:52:27 +02:00
|
|
|
function bot_info(bot_user_id) {
|
|
|
|
const bot_user = bot_data.get(bot_user_id);
|
|
|
|
|
|
|
|
if (!bot_user) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const owner_id = bot_user.owner_id;
|
2020-05-11 00:54:00 +02:00
|
|
|
|
2020-05-08 13:46:28 +02:00
|
|
|
const info = {};
|
|
|
|
|
2020-05-08 15:21:12 +02:00
|
|
|
info.is_bot = true;
|
|
|
|
info.is_admin = false;
|
|
|
|
info.is_guest = false;
|
|
|
|
info.is_active = bot_user.is_active;
|
|
|
|
info.user_id = bot_user.user_id;
|
|
|
|
info.full_name = bot_user.full_name;
|
2020-05-11 00:54:00 +02:00
|
|
|
info.bot_owner_id = owner_id;
|
2020-05-08 13:46:28 +02:00
|
|
|
|
|
|
|
// Convert bot type id to string for viewing to the users.
|
2020-05-08 15:21:12 +02:00
|
|
|
info.bot_type = settings_bots.type_id_to_string(bot_user.bot_type);
|
2020-05-08 13:46:28 +02:00
|
|
|
|
2020-05-11 00:54:00 +02:00
|
|
|
info.bot_owner_full_name = bot_owner_full_name(owner_id);
|
2020-05-08 13:46:28 +02:00
|
|
|
|
2020-05-11 00:54:00 +02:00
|
|
|
if (!info.bot_owner_full_name) {
|
2020-05-08 15:21:12 +02:00
|
|
|
info.no_owner = true;
|
|
|
|
info.bot_owner_full_name = i18n.t("No owner");
|
2020-05-08 13:46:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
info.is_current_user = false;
|
|
|
|
info.can_modify = page_params.is_admin;
|
|
|
|
|
|
|
|
// It's always safe to show the fake email addresses for bot users
|
|
|
|
info.display_email = bot_user.email;
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2020-05-08 15:09:21 +02:00
|
|
|
function get_last_active(user) {
|
|
|
|
const last_active_date = presence.last_active_date(user.user_id);
|
|
|
|
|
|
|
|
if (!last_active_date) {
|
|
|
|
return i18n.t("Unknown");
|
|
|
|
}
|
|
|
|
return timerender.render_now(last_active_date).time_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
function human_info(person) {
|
|
|
|
const info = {};
|
|
|
|
|
2020-05-08 15:21:12 +02:00
|
|
|
info.is_bot = false;
|
|
|
|
info.is_admin = person.is_admin;
|
|
|
|
info.is_guest = person.is_guest;
|
2020-06-03 23:30:34 +02:00
|
|
|
info.is_owner = person.is_owner;
|
2020-06-09 03:07:35 +02:00
|
|
|
info.is_active = people.is_person_active(person.user_id);
|
2020-05-08 15:21:12 +02:00
|
|
|
info.user_id = person.user_id;
|
|
|
|
info.full_name = person.full_name;
|
|
|
|
info.bot_owner_id = person.bot_owner_id;
|
2020-05-08 15:09:21 +02:00
|
|
|
|
|
|
|
info.can_modify = page_params.is_admin;
|
|
|
|
info.is_current_user = people.is_my_user_id(person.user_id);
|
2020-06-06 00:12:52 +02:00
|
|
|
info.cannot_deactivate = info.is_current_user || person.is_owner && !page_params.is_owner;
|
2020-05-08 15:09:21 +02:00
|
|
|
info.display_email = settings_data.email_for_user_settings(person);
|
|
|
|
|
2020-06-09 03:07:35 +02:00
|
|
|
if (info.is_active) {
|
2020-05-08 15:09:21 +02:00
|
|
|
// TODO: We might just want to show this
|
|
|
|
// for deactivated users, too, even though
|
|
|
|
// it might usually just be undefined.
|
|
|
|
info.last_active_date = get_last_active(person);
|
|
|
|
}
|
|
|
|
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
2020-05-20 00:32:34 +02:00
|
|
|
let bot_list_widget;
|
|
|
|
|
2020-05-09 20:06:14 +02:00
|
|
|
section.bots.create_table = () => {
|
2020-05-18 22:36:37 +02:00
|
|
|
loading.make_indicator($('#admin_page_bots_loading_indicator'), {text: 'Loading...'});
|
2019-11-02 00:06:25 +01:00
|
|
|
const $bots_table = $("#admin_bots_table");
|
2020-05-18 22:36:37 +02:00
|
|
|
$bots_table.hide();
|
2020-05-09 20:06:14 +02:00
|
|
|
const bot_user_ids = bot_data.all_user_ids();
|
|
|
|
|
2020-05-20 00:32:34 +02:00
|
|
|
bot_list_widget = list_render.create($bots_table, bot_user_ids, {
|
2017-04-20 21:58:12 +02:00
|
|
|
name: "admin_bot_list",
|
2020-05-10 12:52:27 +02:00
|
|
|
get_item: bot_info,
|
|
|
|
modifier: render_admin_user_list,
|
2020-05-20 00:32:34 +02:00
|
|
|
html_selector: (item) => `tr[data-user-id='${item}']`,
|
2017-04-20 21:58:12 +02:00
|
|
|
filter: {
|
|
|
|
element: $bots_table.closest(".settings-section").find(".search"),
|
2019-12-30 17:44:24 +01:00
|
|
|
predicate: function (item, value) {
|
2020-05-10 12:52:27 +02:00
|
|
|
if (!item) {
|
|
|
|
return false;
|
|
|
|
}
|
js: Convert a.indexOf(…) !== -1 to a.includes(…).
Babel polyfills this for us for Internet Explorer.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
recast.visit(ast, {
visitBinaryExpression(path) {
const { operator, left, right } = path.node;
if (
n.CallExpression.check(left) &&
n.MemberExpression.check(left.callee) &&
!left.callee.computed &&
n.Identifier.check(left.callee.property) &&
left.callee.property.name === "indexOf" &&
left.arguments.length === 1 &&
checkExpression(left.arguments[0]) &&
((["===", "!==", "==", "!=", ">", "<="].includes(operator) &&
n.UnaryExpression.check(right) &&
right.operator == "-" &&
n.Literal.check(right.argument) &&
right.argument.value === 1) ||
([">=", "<"].includes(operator) &&
n.Literal.check(right) &&
right.value === 0))
) {
const test = b.callExpression(
b.memberExpression(left.callee.object, b.identifier("includes")),
[left.arguments[0]]
);
path.replace(
["!==", "!=", ">", ">="].includes(operator)
? test
: b.unaryExpression("!", test)
);
changed = true;
}
this.traverse(path);
},
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-08 04:55:06 +01:00
|
|
|
return item.full_name.toLowerCase().includes(value) ||
|
2020-05-10 12:52:27 +02:00
|
|
|
item.display_email.toLowerCase().includes(value);
|
2017-04-20 21:58:12 +02:00
|
|
|
},
|
2019-01-09 14:30:35 +01:00
|
|
|
onupdate: reset_scrollbar($bots_table),
|
2017-04-20 21:58:12 +02:00
|
|
|
},
|
2019-08-15 07:33:31 +02:00
|
|
|
parent_container: $("#admin-bot-list").expectOne(),
|
2020-04-11 16:23:29 +02:00
|
|
|
init_sort: ['alphabetic', 'full_name'],
|
|
|
|
sort_fields: {
|
2020-05-10 12:52:27 +02:00
|
|
|
email: sort_bot_email,
|
2020-04-11 16:23:29 +02:00
|
|
|
bot_owner: sort_bot_owner,
|
|
|
|
},
|
|
|
|
});
|
2019-08-15 07:33:31 +02:00
|
|
|
|
2020-05-07 15:43:20 +02:00
|
|
|
loading.destroy_indicator($('#admin_page_bots_loading_indicator'));
|
2020-05-18 22:36:37 +02:00
|
|
|
$bots_table.show();
|
2020-05-07 15:43:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
section.active.create_table = (active_users) => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const $users_table = $("#admin_users_table");
|
2020-04-11 16:23:29 +02:00
|
|
|
list_render.create($users_table, active_users, {
|
2017-04-20 21:58:46 +02:00
|
|
|
name: "users_table_list",
|
2020-06-10 19:36:53 +02:00
|
|
|
get_item: people.get_by_user_id,
|
2017-04-20 21:58:46 +02:00
|
|
|
modifier: function (item) {
|
2020-05-08 15:09:21 +02:00
|
|
|
const info = human_info(item);
|
|
|
|
return render_admin_user_list(info);
|
2017-04-20 21:58:46 +02:00
|
|
|
},
|
|
|
|
filter: {
|
|
|
|
element: $users_table.closest(".settings-section").find(".search"),
|
2020-01-13 17:45:53 +01:00
|
|
|
filterer: people.filter_for_user_settings_search,
|
2019-01-09 14:30:35 +01:00
|
|
|
onupdate: reset_scrollbar($users_table),
|
2017-04-20 21:58:46 +02:00
|
|
|
},
|
2019-08-16 06:02:53 +02:00
|
|
|
parent_container: $("#admin-user-list").expectOne(),
|
2020-04-11 16:23:29 +02:00
|
|
|
init_sort: ['alphabetic', 'full_name'],
|
|
|
|
sort_fields: {
|
2020-04-15 15:09:23 +02:00
|
|
|
email: sort_email,
|
2020-04-11 16:23:29 +02:00
|
|
|
last_active: sort_last_active,
|
2020-04-15 15:09:23 +02:00
|
|
|
role: sort_role,
|
2020-04-11 16:23:29 +02:00
|
|
|
},
|
|
|
|
});
|
2019-08-16 06:02:53 +02:00
|
|
|
|
2020-05-07 15:43:20 +02:00
|
|
|
loading.destroy_indicator($('#admin_page_users_loading_indicator'));
|
|
|
|
$("#admin_users_table").show();
|
|
|
|
};
|
|
|
|
|
|
|
|
section.deactivated.create_table = (deactivated_users) => {
|
2019-11-02 00:06:25 +01:00
|
|
|
const $deactivated_users_table = $("#admin_deactivated_users_table");
|
2020-04-11 16:23:29 +02:00
|
|
|
list_render.create($deactivated_users_table, deactivated_users, {
|
2017-04-20 21:47:14 +02:00
|
|
|
name: "deactivated_users_table_list",
|
2020-06-10 19:36:53 +02:00
|
|
|
get_item: people.get_by_user_id,
|
2017-04-20 21:47:14 +02:00
|
|
|
modifier: function (item) {
|
2020-05-08 15:09:21 +02:00
|
|
|
const info = human_info(item);
|
|
|
|
return render_admin_user_list(info);
|
2017-04-20 21:47:14 +02:00
|
|
|
},
|
|
|
|
filter: {
|
|
|
|
element: $deactivated_users_table.closest(".settings-section").find(".search"),
|
2020-01-13 17:45:53 +01:00
|
|
|
filterer: people.filter_for_user_settings_search,
|
2019-01-09 14:30:35 +01:00
|
|
|
onupdate: reset_scrollbar($deactivated_users_table),
|
2017-04-20 21:47:14 +02:00
|
|
|
},
|
2019-08-16 06:18:41 +02:00
|
|
|
parent_container: $("#admin-deactivated-users-list").expectOne(),
|
2020-04-11 16:23:29 +02:00
|
|
|
init_sort: ['alphabetic', 'full_name'],
|
|
|
|
sort_fields: {
|
2020-04-15 15:09:23 +02:00
|
|
|
email: sort_email,
|
2020-04-11 16:23:29 +02:00
|
|
|
role: sort_role,
|
|
|
|
},
|
|
|
|
});
|
2019-08-16 06:18:41 +02:00
|
|
|
|
2017-04-08 20:08:35 +02:00
|
|
|
loading.destroy_indicator($('#admin_page_deactivated_users_loading_indicator'));
|
2018-03-03 08:33:30 +01:00
|
|
|
$("#admin_deactivated_users_table").show();
|
2020-05-07 15:43:20 +02:00
|
|
|
};
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-20 00:32:34 +02:00
|
|
|
exports.update_bot_data = function (bot_user_id) {
|
2020-05-29 20:47:16 +02:00
|
|
|
if (!bot_list_widget) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-20 00:32:34 +02:00
|
|
|
bot_list_widget.render_item(bot_user_id);
|
|
|
|
};
|
|
|
|
|
2020-05-11 12:42:36 +02:00
|
|
|
exports.update_user_data = function (user_id, new_data) {
|
2020-05-09 20:20:26 +02:00
|
|
|
const user_row = get_user_info_row(user_id);
|
|
|
|
|
|
|
|
if (user_row.length === 0) {
|
2020-05-11 12:42:36 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_data.full_name !== undefined) {
|
|
|
|
// Update the full name in the table
|
|
|
|
user_row.find(".user_name").text(new_data.full_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_data.is_active !== undefined) {
|
|
|
|
if (new_data.is_active === false) {
|
|
|
|
// Deactivate the user/bot in the table
|
|
|
|
update_view_on_deactivate(user_row);
|
|
|
|
} else {
|
|
|
|
// Reactivate the user/bot in the table
|
|
|
|
update_view_on_reactivate(user_row);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-30 21:43:19 +02:00
|
|
|
if (new_data.role !== undefined) {
|
2020-05-11 12:42:36 +02:00
|
|
|
user_row.find(".user_role").text(people.get_user_type(user_id));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-05-07 20:19:00 +02:00
|
|
|
function start_data_load() {
|
2018-02-28 19:29:34 +01:00
|
|
|
loading.make_indicator($('#admin_page_users_loading_indicator'), {text: 'Loading...'});
|
|
|
|
loading.make_indicator($('#admin_page_deactivated_users_loading_indicator'), {text: 'Loading...'});
|
2018-03-03 08:33:30 +01:00
|
|
|
$("#admin_deactivated_users_table").hide();
|
|
|
|
$("#admin_users_table").hide();
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-06-09 04:14:32 +02:00
|
|
|
populate_users();
|
2020-05-07 20:19:00 +02:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
function open_human_form(person) {
|
2020-05-09 14:34:04 +02:00
|
|
|
const user_id = person.user_id;
|
|
|
|
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
const html = render_admin_human_form({
|
2020-05-09 14:34:04 +02:00
|
|
|
user_id: user_id,
|
2019-07-08 09:17:59 +02:00
|
|
|
email: person.email,
|
2020-05-09 14:51:08 +02:00
|
|
|
full_name: person.full_name,
|
2020-05-29 16:12:09 +02:00
|
|
|
user_role_values: settings_config.user_role_values,
|
2020-06-03 23:30:34 +02:00
|
|
|
disable_role_dropdown: person.is_owner && !page_params.is_owner,
|
2019-07-08 09:17:59 +02:00
|
|
|
});
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
const div = $(html);
|
2019-11-02 00:06:25 +01:00
|
|
|
const modal_container = $('#user-info-form-modal-container');
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
modal_container.empty().append(div);
|
|
|
|
overlays.open_modal('#admin-human-form');
|
2020-05-29 16:12:09 +02:00
|
|
|
set_user_role_dropdown(person);
|
2020-06-03 23:30:34 +02:00
|
|
|
if (!page_params.is_owner) {
|
|
|
|
$('#user-role-select').find('option[value=' + settings_config.user_role_values.owner.code + ']').hide();
|
|
|
|
}
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
|
2020-05-09 14:34:04 +02:00
|
|
|
const element = "#admin-human-form .custom-profile-field-form";
|
|
|
|
$(element).html("");
|
|
|
|
settings_account.append_custom_profile_fields(element, user_id);
|
|
|
|
settings_account.initialize_custom_date_type_fields(element);
|
|
|
|
const pills = settings_account.initialize_custom_user_type_fields(
|
|
|
|
element,
|
|
|
|
user_id,
|
|
|
|
true,
|
|
|
|
false
|
|
|
|
);
|
|
|
|
|
|
|
|
return {
|
|
|
|
modal: div,
|
|
|
|
fields_user_pills: pills,
|
|
|
|
};
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
}
|
|
|
|
|
2020-05-09 14:40:22 +02:00
|
|
|
function get_human_profile_data(fields_user_pills) {
|
|
|
|
/*
|
|
|
|
This formats custom profile field data to send to the server.
|
|
|
|
See render_admin_human_form and open_human_form
|
|
|
|
to see how the form is built.
|
|
|
|
|
|
|
|
TODO: Ideally, this logic would be cleaned up or deduplicated with
|
|
|
|
the settings_account.js logic.
|
|
|
|
*/
|
|
|
|
const new_profile_data = [];
|
|
|
|
$("#admin-human-form .custom_user_field_value").each(function () {
|
|
|
|
// Remove duplicate datepicker input element generated flatpicker library
|
|
|
|
if (!$(this).hasClass("form-control")) {
|
|
|
|
new_profile_data.push({
|
|
|
|
id: parseInt($(this).closest(".custom_user_field").attr("data-field-id"), 10),
|
|
|
|
value: $(this).val(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// Append user type field values also
|
|
|
|
for (const [field_id, field_pills] of fields_user_pills) {
|
|
|
|
if (field_pills) {
|
|
|
|
const user_ids = user_pill.get_user_ids(field_pills);
|
|
|
|
new_profile_data.push({
|
|
|
|
id: field_id,
|
|
|
|
value: user_ids,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new_profile_data;
|
|
|
|
}
|
|
|
|
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
function open_bot_form(person) {
|
|
|
|
const html = render_admin_bot_form({
|
|
|
|
user_id: person.user_id,
|
|
|
|
email: person.email,
|
2020-05-09 14:51:08 +02:00
|
|
|
full_name: person.full_name,
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
});
|
|
|
|
const div = $(html);
|
|
|
|
const modal_container = $('#user-info-form-modal-container');
|
|
|
|
modal_container.empty().append(div);
|
|
|
|
overlays.open_modal('#admin-bot-form');
|
2019-07-08 09:17:59 +02:00
|
|
|
|
2020-05-11 14:30:46 +02:00
|
|
|
// NOTE: building `owner_dropdown` is quite expensive!
|
|
|
|
const owner_id = bot_data.get(person.user_id).owner_id;
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
|
2020-05-30 04:21:15 +02:00
|
|
|
const user_ids = people.get_active_human_ids();
|
|
|
|
const users_list = user_ids.map(user_id => ({
|
|
|
|
name: people.get_full_name(user_id),
|
|
|
|
value: user_id.toString(),
|
|
|
|
}));
|
2020-05-19 21:52:27 +02:00
|
|
|
const opts = {
|
|
|
|
widget_name: 'edit_bot_owner',
|
2020-05-30 04:21:15 +02:00
|
|
|
data: users_list,
|
2020-05-19 21:52:27 +02:00
|
|
|
default_text: i18n.t("No owner"),
|
|
|
|
value: owner_id,
|
|
|
|
};
|
|
|
|
const owner_widget = dropdown_list_widget(opts);
|
2020-05-11 14:30:46 +02:00
|
|
|
|
|
|
|
return {
|
|
|
|
modal: div,
|
2020-05-19 21:52:27 +02:00
|
|
|
owner_widget,
|
2020-05-11 14:30:46 +02:00
|
|
|
};
|
2019-07-08 09:17:59 +02:00
|
|
|
}
|
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function confirm_deactivation(row, user_id, status_field) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const modal_elem = $("#deactivation_user_modal").expectOne();
|
2019-03-19 12:39:06 +01:00
|
|
|
|
2020-05-08 21:10:43 +02:00
|
|
|
function set_fields() {
|
2020-02-05 14:30:59 +01:00
|
|
|
const user = people.get_by_user_id(user_id);
|
2019-03-19 12:39:06 +01:00
|
|
|
modal_elem.find(".email").text(user.email);
|
|
|
|
modal_elem.find(".user_name").text(user.full_name);
|
2020-05-08 21:10:43 +02:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-08 21:10:43 +02:00
|
|
|
function handle_confirm() {
|
2019-11-02 00:06:25 +01:00
|
|
|
const row = get_user_info_row(user_id);
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2019-03-19 12:39:06 +01:00
|
|
|
modal_elem.modal("hide");
|
2019-11-02 00:06:25 +01:00
|
|
|
const row_deactivate_button = row.find("button.deactivate");
|
2019-03-18 12:16:06 +01:00
|
|
|
row_deactivate_button.prop("disabled", true).text(i18n.t("Working…"));
|
2019-11-02 00:06:25 +01:00
|
|
|
const opts = {
|
2019-03-18 12:16:06 +01:00
|
|
|
success_continuation: function () {
|
2019-03-19 12:57:15 +01:00
|
|
|
update_view_on_deactivate(row);
|
2019-03-18 12:16:06 +01:00
|
|
|
},
|
|
|
|
error_continuation: function () {
|
|
|
|
row_deactivate_button.text(i18n.t("Deactivate"));
|
|
|
|
},
|
2019-01-14 14:04:27 +01:00
|
|
|
};
|
2019-11-02 00:06:25 +01:00
|
|
|
const url = '/json/users/' + encodeURIComponent(user_id);
|
2020-05-07 23:07:34 +02:00
|
|
|
settings_ui.do_settings_change(channel.del, url, {}, status_field, opts);
|
2019-01-14 14:04:27 +01:00
|
|
|
|
2020-05-08 21:10:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
modal_elem.modal("hide");
|
|
|
|
modal_elem.off('click', '.do_deactivate_button');
|
|
|
|
set_fields();
|
|
|
|
modal_elem.on('click', '.do_deactivate_button', handle_confirm);
|
|
|
|
modal_elem.modal("show");
|
|
|
|
}
|
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function handle_deactivation(tbody, status_field) {
|
2020-05-07 20:19:00 +02:00
|
|
|
tbody.on("click", ".deactivate", function (e) {
|
2020-05-08 21:10:43 +02:00
|
|
|
// This click event must not get propagated to parent container otherwise the modal
|
|
|
|
// will not show up because of a call to `close_active_modal` in `settings.js`.
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
const row = $(e.target).closest(".user_row");
|
|
|
|
const user_id = row.data('user-id');
|
2020-05-07 23:07:34 +02:00
|
|
|
confirm_deactivation(row, user_id, status_field);
|
2017-04-08 20:08:35 +02:00
|
|
|
});
|
2020-05-07 16:34:49 +02:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function handle_bot_deactivation(tbody, status_field) {
|
2020-05-07 20:19:00 +02:00
|
|
|
tbody.on("click", ".deactivate", function (e) {
|
2017-04-08 20:08:35 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const button_elem = $(e.target);
|
|
|
|
const row = button_elem.closest(".user_row");
|
2020-01-16 20:40:20 +01:00
|
|
|
const bot_id = parseInt(row.attr("data-user-id"), 10);
|
2019-11-02 00:06:25 +01:00
|
|
|
const url = '/json/bots/' + encodeURIComponent(bot_id);
|
2019-03-18 12:05:52 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const opts = {
|
2019-03-18 11:07:51 +01:00
|
|
|
success_continuation: function () {
|
|
|
|
update_view_on_deactivate(row);
|
|
|
|
},
|
2019-03-18 12:05:52 +01:00
|
|
|
error_continuation: function (xhr) {
|
|
|
|
ui_report.generic_row_button_error(xhr, button_elem);
|
|
|
|
},
|
2019-01-14 14:04:27 +01:00
|
|
|
};
|
2020-05-07 23:07:34 +02:00
|
|
|
settings_ui.do_settings_change(channel.del, url, {}, status_field, opts);
|
2017-04-08 20:08:35 +02:00
|
|
|
|
|
|
|
});
|
2020-05-07 16:34:49 +02:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function handle_reactivation(tbody, status_field) {
|
2020-05-07 20:19:00 +02:00
|
|
|
tbody.on("click", ".reactivate", function (e) {
|
2017-04-08 20:08:35 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
// Go up the tree until we find the user row, then grab the email element
|
2019-11-02 00:06:25 +01:00
|
|
|
const button_elem = $(e.target);
|
|
|
|
const row = button_elem.closest(".user_row");
|
2020-01-16 20:40:20 +01:00
|
|
|
const user_id = parseInt(row.attr("data-user-id"), 10);
|
2019-11-02 00:06:25 +01:00
|
|
|
const url = '/json/users/' + encodeURIComponent(user_id) + "/reactivate";
|
|
|
|
const data = {};
|
|
|
|
|
|
|
|
const opts = {
|
2019-03-18 12:05:52 +01:00
|
|
|
success_continuation: function () {
|
|
|
|
update_view_on_reactivate(row);
|
|
|
|
},
|
|
|
|
error_continuation: function (xhr) {
|
|
|
|
ui_report.generic_row_button_error(xhr, button_elem);
|
|
|
|
},
|
2019-01-14 14:04:27 +01:00
|
|
|
};
|
2019-03-18 12:05:52 +01:00
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
settings_ui.do_settings_change(channel.post, url, data, status_field, opts);
|
2017-04-08 20:08:35 +02:00
|
|
|
});
|
2020-05-07 16:34:49 +02:00
|
|
|
}
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-07 20:19:00 +02:00
|
|
|
function handle_bot_owner_profile(tbody) {
|
|
|
|
tbody.on('click', '.user_row .view_user_profile', function (e) {
|
2020-03-05 20:02:54 +01:00
|
|
|
const owner_id = parseInt($(e.target).attr('data-owner-id'), 10);
|
2020-02-05 14:30:59 +01:00
|
|
|
const owner = people.get_by_user_id(owner_id);
|
2019-11-25 09:08:18 +01:00
|
|
|
popovers.show_user_profile(owner);
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
2020-05-07 16:34:49 +02:00
|
|
|
}
|
2019-11-25 09:08:18 +01:00
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function handle_human_form(tbody, status_field) {
|
2020-05-07 20:19:00 +02:00
|
|
|
tbody.on("click", ".open-user-form", function (e) {
|
2020-01-14 19:22:48 +01:00
|
|
|
const user_id = parseInt($(e.currentTarget).attr("data-user-id"), 10);
|
2020-02-05 14:30:59 +01:00
|
|
|
const person = people.get_by_user_id(user_id);
|
2018-07-30 09:22:57 +02:00
|
|
|
|
|
|
|
if (!person) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-09 14:34:04 +02:00
|
|
|
const ret = open_human_form(person);
|
|
|
|
const modal = ret.modal;
|
|
|
|
const fields_user_pills = ret.fields_user_pills;
|
2017-04-08 20:08:35 +02:00
|
|
|
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
modal.find('.submit_human_change').on("click", function (e) {
|
2017-04-08 20:08:35 +02:00
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
2020-05-29 16:12:09 +02:00
|
|
|
const role = parseInt(modal.find('#user-role-select').val().trim(), 10);
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
const full_name = modal.find("input[name='full_name']");
|
2020-05-09 14:40:22 +02:00
|
|
|
const profile_data = get_human_profile_data(fields_user_pills);
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
|
|
|
|
const url = "/json/users/" + encodeURIComponent(user_id);
|
|
|
|
const data = {
|
|
|
|
full_name: JSON.stringify(full_name.val()),
|
2020-05-29 16:12:09 +02:00
|
|
|
role: JSON.stringify(role),
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
profile_data: JSON.stringify(profile_data),
|
|
|
|
};
|
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
settings_ui.do_settings_change(channel.patch, url, data, status_field);
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
overlays.close_modal('#admin-human-form');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
function handle_bot_form(tbody, status_field) {
|
2020-05-07 20:19:00 +02:00
|
|
|
tbody.on("click", ".open-user-form", function (e) {
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
const user_id = parseInt($(e.currentTarget).attr("data-user-id"), 10);
|
|
|
|
const bot = people.get_by_user_id(user_id);
|
|
|
|
|
|
|
|
if (!bot) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-19 21:52:27 +02:00
|
|
|
const {modal, owner_widget} = open_bot_form(bot);
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
|
|
|
|
modal.find('.submit_bot_change').on("click", function (e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
const full_name = modal.find("input[name='full_name']");
|
|
|
|
|
|
|
|
const url = "/json/bots/" + encodeURIComponent(user_id);
|
|
|
|
const data = {
|
|
|
|
full_name: full_name.val(),
|
|
|
|
};
|
|
|
|
|
2020-05-19 21:52:27 +02:00
|
|
|
const human_user_id = owner_widget.value();
|
2020-05-11 14:30:46 +02:00
|
|
|
if (human_user_id) {
|
|
|
|
data.bot_owner_id = human_user_id;
|
2017-04-08 20:08:35 +02:00
|
|
|
}
|
|
|
|
|
2020-05-07 23:07:34 +02:00
|
|
|
settings_ui.do_settings_change(channel.patch, url, data, status_field);
|
user settings: Separate code for bot form.
When editing a bot, there are only two fields
that are similar to humans--full name and
email--which are trivial.
Before this commit we used a single codepath
to build the human form and the bot form.
Now we have two simple codepaths.
The tricky nature of the code had already led
to ugly things for the bot codepath that
fortunately weren't user facing, but which
were distracting:
- For bots we would needlessly set things
like is_admin, is_guest in the template
data.
- For bots we would needlessly try to update
custom profile fields.
The code that differs between bots and humans
is nontrivial, and the code was both hard to read
and hard to improve:
- Humans don't have bot owners.
- Bots don't have custom profile fields.
The bot-owner code is nontrivial for performance
reasons. In a big realm there are tens of thousands
of potential bot owners. We avoid the most egregious
performance problems (i.e we don't have multiple
copies of the dropdown), but we may still want
to refine that (at least adding a spinner).
The custom-profile-fields code is nontrivial due
to the dynamic nature of custom profile fields,
which can bring in specialized widgets like
pill fields.
Now each form corresponds to a single endpoint:
* human -> /json/users
* bot -> /json/bots
Before we had a lot of conditional logic in
the template, the code to build to views, and
the code to submit the data. Now everything is
much flatter.
The human code is still a bit messy (more work
coming on that), but the bot code is fairly
pristine. All three components of the bot code
fit on a page, and there are no conditionals:
- admin_bot_form.hbs
- open_bot_form
- handle_bot_form
We may want to grow out the bot code a bit
to allow admins to do more things, such as
adding services, and this will be easier now.
It would also be easier for us now to share
widgets with the per-user bot settings.
Note that the form for editing human data will
continue to be invoked from two panels:
- Users
- Deactivated users
There are some minor differences between
users and deactivated users, but the shape of
the data is the same for both, so that's still
all one codepath.
We eliminate `reset_edit_user` here, since
it was never used.
One nice thing about these forms was that they
had very little custom CSS attached to them
(at form-level specificity), and it turned out
all the custom CSS was for the human-specific
form.
2020-05-09 12:13:03 +02:00
|
|
|
overlays.close_modal('#admin-bot-form');
|
2017-04-08 20:08:35 +02:00
|
|
|
});
|
|
|
|
});
|
2020-05-07 16:34:49 +02:00
|
|
|
}
|
|
|
|
|
2020-05-07 20:19:00 +02:00
|
|
|
section.active.handle_events = () => {
|
|
|
|
const tbody = $('#admin_users_table').expectOne();
|
2020-05-07 23:07:34 +02:00
|
|
|
const status_field = $('#user-field-status').expectOne();
|
|
|
|
|
|
|
|
handle_deactivation(tbody, status_field);
|
|
|
|
handle_reactivation(tbody, status_field);
|
|
|
|
handle_human_form(tbody, status_field);
|
2020-05-07 20:19:00 +02:00
|
|
|
};
|
2017-04-08 20:08:35 +02:00
|
|
|
|
2020-05-07 20:19:00 +02:00
|
|
|
section.deactivated.handle_events = () => {
|
|
|
|
const tbody = $('#admin_deactivated_users_table').expectOne();
|
2020-05-07 23:07:34 +02:00
|
|
|
const status_field = $("#deactivated-user-field-status").expectOne();
|
|
|
|
|
|
|
|
handle_deactivation(tbody, status_field);
|
|
|
|
handle_reactivation(tbody, status_field);
|
|
|
|
handle_human_form(tbody, status_field);
|
2020-05-07 20:19:00 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
section.bots.handle_events = () => {
|
|
|
|
const tbody = $('#admin_bots_table').expectOne();
|
2020-05-07 23:07:34 +02:00
|
|
|
const status_field = $("#bot-field-status").expectOne();
|
|
|
|
|
2020-05-07 20:19:00 +02:00
|
|
|
handle_bot_owner_profile(tbody);
|
2020-05-07 23:07:34 +02:00
|
|
|
handle_bot_deactivation(tbody, status_field);
|
|
|
|
handle_reactivation(tbody, status_field);
|
|
|
|
handle_bot_form(tbody, status_field);
|
2020-05-07 20:19:00 +02:00
|
|
|
};
|
|
|
|
|
2020-05-09 20:06:14 +02:00
|
|
|
exports.set_up_humans = function () {
|
2020-05-07 20:19:00 +02:00
|
|
|
start_data_load();
|
|
|
|
section.active.handle_events();
|
|
|
|
section.deactivated.handle_events();
|
2020-05-09 20:06:14 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.set_up_bots = function () {
|
2020-05-07 20:19:00 +02:00
|
|
|
section.bots.handle_events();
|
2020-05-09 20:06:14 +02:00
|
|
|
section.bots.create_table();
|
2017-04-08 20:08:35 +02:00
|
|
|
};
|
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
window.settings_users = exports;
|