TeaWeb/shared/js/ui/modal/ModalBanList.ts

921 lines
43 KiB
TypeScript
Raw Normal View History

2019-10-13 21:33:07 +02:00
/// <reference path="../../ConnectionHandler.ts" />
/// <reference path="../../ui/elements/modal.ts" />
/// <reference path="../../i18n/localize.ts" />
/// <reference path="../../proto.ts" />
namespace Modals {
2019-09-12 23:59:35 +02:00
export function openBanList(client: ConnectionHandler) {
let modal: Modal;
let _callback_bans;
let _callback_triggers;
const single_ban_handler: connection.SingleCommandHandler = {
command: "notifybanlist",
function: command => {
const json = command.arguments;
let bans: BanEntry[] = [];
for(const entry of json) {
bans.push({
server_id: parseInt(entry["sid"]),
banid: parseInt(entry["banid"]),
ip: entry["ip"],
name: entry["name"],
unique_id: entry["uid"],
hardware_id: entry["hwid"],
timestamp_created: (parseInt(entry["created"]) * 1000),
timestamp_expire: (parseInt(entry["duration"]) > 0 ? parseInt(entry["created"]) * 1000 + parseInt(entry["duration"]) * 1000 : 0),
invoker_name: entry["invokername"],
invoker_database_id: parseInt(entry["invokercldbid"]),
invoker_unique_id: entry["invokeruid"],
reason: entry["reason"],
enforcements: parseInt(entry["enforcements"]),
flag_own: entry["invokeruid"] == client.getClient().properties.client_unique_identifier
});
}
_callback_bans(bans);
return false; /* do not remove me */
}
};
const single_trigger_handler: connection.SingleCommandHandler = {
command: "notifybantriggerlist",
function: command => {
//TODO: Test the server id in the response?
const json = command.arguments;
let triggers: TriggerEntry[] = [];
for(const entry of json) {
triggers.push({
unique_id: entry["client_unique_identifier"],
client_nickname: entry["client_nickname"],
hardware_id: entry["client_hardware_identifier"],
connection_ip: entry["connection_client_ip"],
timestamp: parseInt(entry["timestamp"])
});
}
_callback_triggers(triggers);
return false; /* do not remove me */
}
};
const controller: BanListController = {
request_list(_callback): Promise<void> {
_callback_bans = _callback;
return new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => {
cleanup();
reject("timeout");
}, 2500);
const cleanup = () => {
clearTimeout(timeout);
_callback_bans = undefined;
};
Promise.all([
client.serverConnection.send_command("banlist", { sid: 0 }, {process_result: false}).catch(error => {
//TODO: May lookup for permissions
}),
client.serverConnection.send_command("banlist").catch(async error => {
if(error instanceof CommandResult)
if(error.id === ErrorID.EMPTY_RESULT)
return;
throw error;
})
]).then(() => {
if(_callback_bans) resolve();
cleanup();
}).catch(error => {
if(_callback_bans) reject(error);
cleanup();
});
});
},
request_trigger_list(ban, _callback): Promise<void> {
_callback_triggers = _callback;
return new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => {
cleanup();
reject("timeout");
}, 2500);
const cleanup = () => {
clearTimeout(timeout);
_callback_triggers = undefined;
};
const data = {banid: ban.ban_id};
if(typeof ban.server_id !== "undefined")
data["sid"] = ban.server_id;
client.serverConnection.send_command("bantriggerlist", data).catch(async error => {
if(error instanceof CommandResult)
if(error.id === ErrorID.EMPTY_RESULT)
return;
throw error;
}).then(() => {
if(_callback_triggers) resolve();
cleanup();
}).catch(error => {
if(_callback_triggers) reject(error);
cleanup();
});
});
},
async max_bantime(): Promise<number> {
const value = client.permissions.neededPermission(PermissionType.I_CLIENT_BAN_MAX_BANTIME).value || 0;
return value == -2 ? 0 : value;
},
async permission_add(): Promise<boolean[]> {
return [
client.permissions.neededPermission(PermissionType.B_CLIENT_BAN_CREATE).granted(1),
client.permissions.neededPermission(PermissionType.B_CLIENT_BAN_CREATE_GLOBAL).granted(1)
];
},
async permission_edit(): Promise<boolean[]> {
return [
client.permissions.neededPermission(PermissionType.B_CLIENT_BAN_EDIT).granted(1),
client.permissions.neededPermission(PermissionType.B_CLIENT_BAN_EDIT_GLOBAL).granted(1) && false
];
},
add_ban(entry: BanEntry): Promise<void> {
const data = {};
if(entry.ip) data["ip"] = entry.ip;
if(entry.name) data["name"] = entry.name;
if(entry.unique_id) data["uid"] = entry.unique_id;
if(entry.hardware_id) data["hwid"] = entry.hardware_id;
if(entry.reason) data["banreason"] = entry.reason;
if(entry.timestamp_expire) data["time"] = Math.floor((entry.timestamp_expire - entry.timestamp_created) / 1000);
if(typeof(entry.server_id) === "number") data["sid"] = entry.server_id;
return client.serverConnection.send_command("banadd", data).then(e => { if(!e.success) throw e; });
},
edit_ban(data: any): Promise<void> {
return client.serverConnection.send_command("banedit", data).then(e => { if(!e.success) throw e; });
},
delete_ban(entry_id, server_id): Promise<void> {
const data = {
banid: entry_id
};
if(typeof(server_id) === "number")
data["sid"] = server_id;
return client.serverConnection.send_command("bandel", data).then(e => { if(!e.success) throw e; });
}
};
modal = createModal({
header: tr("Server Banlist"),
body: () => generate_dom(controller),
footer: null,
width: '60em'
});
client.serverConnection.command_handler_boss().register_single_handler(single_ban_handler);
client.serverConnection.command_handler_boss().register_single_handler(single_trigger_handler);
modal.close_listener.push(() => {
client.serverConnection.command_handler_boss().remove_single_handler(single_ban_handler);
client.serverConnection.command_handler_boss().remove_single_handler(single_trigger_handler);
});
//TODO: Test without dividerfy!
modal.htmlTag.dividerfy();
modal.htmlTag.find(".modal-body").addClass("modal-ban-list");
modal.open();
}
interface BanEntry {
server_id: number;
banid: number;
name?: string;
name_type?: number;
unique_id?: string;
ip?: string;
hardware_id?: string;
reason: string;
invoker_name: string;
invoker_unique_id?: string;
invoker_database_id?: number;
2019-09-12 23:59:35 +02:00
timestamp_created: number;
timestamp_expire: number;
enforcements: number;
flag_own?: boolean;
}
2019-09-12 23:59:35 +02:00
interface TriggerEntry {
unique_id?: string;
client_nickname?: string;
hardware_id?: string;
connection_ip: string;
timestamp: number;
}
2019-09-12 23:59:35 +02:00
interface BanListController {
request_list(callback_bans: (entries: BanEntry[]) => any) : Promise<void>;
request_trigger_list(ban: {ban_id: number, server_id: number | undefined}, callback_triggers: (entries: TriggerEntry[]) => any) : Promise<void>;
max_bantime() : Promise<number>;
permission_edit() : Promise<boolean[]>;
permission_add() : Promise<boolean[]>;
add_ban(entry: BanEntry) : Promise<void>;
edit_ban(data: any) : Promise<void>;
delete_ban(entry_id: number, server_id: number | undefined) : Promise<void>;
}
//Note: This object must be sorted (from shortest to longest)!
2019-09-19 01:25:57 +02:00
export const duration_data = {
2019-09-12 23:59:35 +02:00
"sec": {
"text": tr("Seconds"),
"1-text": tr("Second"),
scale: 1
},
"min": {
"text": tr("Minutes"),
"1-text": tr("Minute"),
scale: 60
},
"hours": {
"text": tr("Hours"),
"1-text": tr("Hour"),
scale: 3600
},
"days": {
"text": tr("Days"),
"1-text": tr("Day"),
scale: 86400
},
};
function generate_dom(controller: BanListController) : JQuery {
const template = $("#tmpl_ban_list").renderTag();
let callback_ban_filter: ((text: string, flag_own: boolean, highlight_own: boolean) => boolean)[] = [];
let callback_trigger_filter: ((text: string) => boolean)[] = [];
let selected_ban: BanEntry | undefined;
let update_edit_window: (switch_to: boolean) => any;
let update_ban_filter: () => any;
let update_trigger_filter: () => any;
const container_ban = template.find(".container-banlist");
const container_ban_entries = container_ban.find(".container-list .body");
const container_ban_entries_empty = container_ban.find(".container-list .container-empty");
const container_ban_entries_error = container_ban.find(".container-list .container-error");
const container_trigger = template.find(".container-triggerlist").hide();
const container_trigger_entries = container_trigger.find(".container-list .body");
const container_trigger_entries_empty = container_trigger.find(".container-list .container-empty");
const container_trigger_entries_error = container_trigger.find(".container-list .container-error");
const button_apply = template.find(".button-apply");
let button_apply_state = [false, false]; /* first index is add; second index is edit */
let update_category_inputs: (() => any)[] = [undefined, undefined];
let button_apply_state_index = 1;
const category_add = template.find(".left .head .category-add");
const category_edit = template.find(".left .head .category-edit");
const container_add = template.find(".left .container-add");
const container_add_no_permissions = template.find(".left .container-add .container-no-permissions");
const container_edit = template.find(".left .container-edit");
const seperator_top = template.find(".container-seperator .top");
/* [local; global] */
let permission_edit: boolean[] = [false, false], permission_add: boolean[] = [false, false];
container_add_no_permissions.hide();
controller.permission_add().then(result => permission_add = result).catch(error => {
log.error(LogCategory.CLIENT, tr("Failed to query ban add permissions: %o"), error);
}).then(() => {
if(permission_add[0] !== permission_add[1]) {
const input_global = container_add.find(".group-global input");
input_global.prop("checked", permission_add[1]).prop("disabled", true).firstParent(".checkbox").addClass("disabled");
} else if(!permission_add[0])
container_add_no_permissions.show();
});
2019-09-12 23:59:35 +02:00
controller.permission_edit().then(result => permission_edit = result).catch(error => {
log.error(LogCategory.CLIENT, tr("Failed to query ban edit permissions: %o"), error);
}).then(() => {
if(selected_ban) update_edit_window(false);
});
2019-09-12 23:59:35 +02:00
/* category switch */
{
category_add.on('click', event => {
container_add.removeClass("hidden");
category_add.addClass("selected");
2019-09-12 23:59:35 +02:00
container_edit.addClass("hidden");
category_edit.removeClass("selected");
2019-09-12 23:59:35 +02:00
seperator_top.css({opacity: 1});
2019-09-12 23:59:35 +02:00
button_apply_state_index = 0;
button_apply.prop("disabled", !button_apply_state[0]).text(tr("Add ban"));
update_category_inputs[button_apply_state_index]();
});
2019-09-12 23:59:35 +02:00
category_edit.on('click', event => {
if(!selected_ban) return;
2019-09-12 23:59:35 +02:00
container_add.addClass("hidden");
category_add.removeClass("selected");
container_edit.removeClass("hidden");
category_edit.addClass("selected");
seperator_top.css({opacity: 0});
button_apply_state_index = 1;
button_apply.prop("disabled", !button_apply_state[1]).text(tr("Save ban"));
update_category_inputs[button_apply_state_index]();
});
}
const build_ban_entry = (entry: BanEntry, selected: boolean) => {
let button_delete;
const tag = $.spawn("div").addClass("entry" + (entry.server_id > 0 ? "" : " global") + (selected ? " selected" : "")).append(
$.spawn("div").addClass("column column-key").append(
entry.name ? $.spawn("div").append(entry.name) : undefined,
entry.ip ? $.spawn("div").append(entry.ip) : undefined,
entry.unique_id ? $.spawn("div").append(entry.unique_id) : undefined,
entry.hardware_id ? $.spawn("div").append(entry.hardware_id) : undefined
),
$.spawn("div").addClass("column column-reason").text(entry.reason),
$.spawn("div").addClass("column column-expires").text(entry.timestamp_expire ? moment(entry.timestamp_expire).format('DD.MM.YYYY hh:mm') : tr("Never")),
$.spawn("div").addClass("column column-delete").append(
button_delete = $.spawn("div").addClass("button-delete").append(
$.spawn("div").addClass("icon_em client-delete")
)
)
);
tag.on('click', event => {
if(selected_ban === entry || event.isDefaultPrevented()) return;
selected_ban = entry;
container_ban_entries.find(".entry.selected").removeClass("selected");
tag.addClass("selected");
update_edit_window(true);
});
button_delete.on('click', event => {
event.preventDefault();
controller.delete_ban(entry.banid, entry.server_id).then(() => {
tag.css({opacity: 1}).animate({opacity: 0}, 250, () => tag.animate({"max-height": 0}, 250, () => tag.remove()));
if(entry === selected_ban) {
selected_ban = undefined;
update_edit_window(false);
}
}).catch(error => {
log.error(LogCategory.CLIENT, tr("Failed to delete ban: %o"), error);
if(error instanceof CommandResult)
error = error.id === ErrorID.PERMISSION_ERROR ? "no permissions" : error.extra_message || error.message;
createErrorModal(tr("Failed to delete ban"), MessageHelper.formatMessage(tr("Failed to delete ban. {:br:}Error: {}"), error)).open();
});
});
2019-09-12 23:59:35 +02:00
if(selected) {
selected_ban = entry;
update_edit_window(false);
2019-02-23 14:27:58 +01:00
}
2019-09-12 23:59:35 +02:00
const lower_mesh =
(entry.reason || "").toLowerCase() + " " +
(entry.unique_id || "").toLowerCase() + " " +
(entry.name || "").toLowerCase() + " " +
(entry.ip || "").toLowerCase() + " " +
(entry.hardware_id || "").toLowerCase();
callback_ban_filter.push((text, flag_own, highlight_own) => {
if(text && lower_mesh.indexOf(text) == -1) {
tag.hide();
return false;
}
2019-09-12 23:59:35 +02:00
if(flag_own && !entry.flag_own) {
tag.hide();
return false;
}
2019-09-12 23:59:35 +02:00
2019-10-13 21:33:07 +02:00
tag.show().toggleClass(
"highlight",
highlight_own &&
entry.flag_own
);
2019-09-12 23:59:35 +02:00
return true;
});
2019-09-12 23:59:35 +02:00
return tag;
};
2019-09-12 23:59:35 +02:00
const update_banlist = (selected_ban?: number) => {
callback_ban_filter = [];
2019-09-12 23:59:35 +02:00
container_ban_entries.find(".entry").remove();
container_ban_entries_error.hide();
container_ban_entries_empty.show().find("a").text(tr("Loading..."));
2019-09-12 23:59:35 +02:00
let bans = [];
controller.request_list(_bans => bans.push(..._bans)).then(() => {
if(bans.length) {
container_ban_entries.append(...bans.map(e => build_ban_entry(e, e.banid === selected_ban)));
container_ban_entries_empty.hide();
} else {
container_ban_entries_empty.find("a").text(tr("No bans registered"));
}
2019-09-12 23:59:35 +02:00
update_ban_filter();
}).catch(error => {
log.info(LogCategory.CLIENT, tr("Failed to update ban list: %o"), error);
if(error instanceof CommandResult)
error = error.id === ErrorID.PERMISSION_ERROR ? tr("no permissions") : error.extra_message || error.message;
container_ban_entries_error.show().find("a").text(tr("Failed to receive banlist: ") + error);
container_ban_entries_empty.hide();
});
};
2019-09-12 23:59:35 +02:00
const build_trigger_entry = (entry: TriggerEntry) => {
const spawn_key_value = (key, value, reason) => {
return $.spawn("div").addClass("property").toggleClass("highlighted", reason).append(
$.spawn("div").addClass("key").text(key + ": "),
$.spawn("div").addClass("value").text(value)
);
};
let cause_name = !!selected_ban.name && !!entry.client_nickname.match(selected_ban.name);
let cause_uid = !cause_name && !!selected_ban.unique_id && selected_ban.unique_id.toLowerCase() === (entry.unique_id || "").toLowerCase();
let cause_ip = !cause_uid && !!selected_ban.ip && selected_ban.ip.toLowerCase() === (entry.connection_ip || "").toLowerCase();
let cause_hwid = !cause_ip && !!selected_ban.hardware_id && selected_ban.hardware_id.toLowerCase() === (entry.hardware_id || "").toLowerCase();
/* we guess that IP is the cause because we dont see the IP and there is no other reason */
if(!cause_name && !cause_uid && !cause_ip && !cause_hwid && entry.connection_ip === "hidden")
cause_ip = true;
const time_str = moment(entry.timestamp).format('DD.MM.YYYY hh:mm');
const tag = $.spawn("div").addClass("entry").append(
$.spawn("div").addClass("column column-properties").append(
entry.client_nickname ? spawn_key_value(tr("Nickname"), entry.client_nickname, cause_name) : undefined,
entry.connection_ip ? spawn_key_value(tr("IP"), entry.connection_ip, cause_ip) : undefined,
entry.unique_id ? spawn_key_value(tr("Unique ID"), entry.unique_id, cause_uid) : undefined,
entry.hardware_id ? spawn_key_value(tr("Hardware ID"), entry.hardware_id, cause_hwid) : undefined
),
$.spawn("div").addClass("column column-timestamp").text(time_str)
);
const lower_mesh =
(entry.unique_id || "").toLowerCase() + " " +
(entry.client_nickname || "").toLowerCase() + " " +
(entry.connection_ip || "").toLowerCase() + " " +
(entry.hardware_id || "").toLowerCase() + " " +
time_str + " " +
entry.timestamp;
callback_trigger_filter.push(text => {
if(text && lower_mesh.indexOf(text) == -1) {
tag.hide();
return false;
}
2019-09-12 23:59:35 +02:00
tag.show();
return true;
});
return tag;
};
2019-09-12 23:59:35 +02:00
const update_triggerlist = () => {
callback_trigger_filter = [];
container_trigger_entries.find(".entry").remove();
container_trigger_entries_error.hide();
container_trigger_entries_empty.show().find("a").text(tr("Loading..."));
let triggers = [];
controller.request_trigger_list({
ban_id: selected_ban.banid,
server_id: selected_ban.server_id
}, _triggers => triggers.push(..._triggers)).then(() => {
if(triggers.length) {
container_trigger_entries.append(...triggers.sort((a, b) => b.timestamp - a.timestamp).map(e => build_trigger_entry(e)));
container_trigger_entries_empty.hide();
} else {
container_trigger_entries_empty.find("a").text(tr("No triggers logged"));
}
2019-09-12 23:59:35 +02:00
update_trigger_filter();
}).catch(error => {
log.info(LogCategory.CLIENT, tr("Failed to update trigger list: %o"), error);
if(error instanceof CommandResult)
error = error.id === ErrorID.PERMISSION_ERROR ? tr("no permissions") : error.extra_message || error.message;
container_trigger_entries_error.show().find("a").text(tr("Failed to receive trigger list: ") + error);
container_trigger_entries_empty.hide();
});
};
2019-09-12 23:59:35 +02:00
const show_triggerlist = () => {
container_trigger.show();
};
2019-09-12 23:59:35 +02:00
/* general input field rules */
const initialize_fields = (tag: JQuery, index: number) => {
const input_name = tag.find(".group-name input").on('change keyup', () => update_category_inputs[index]());
const input_ip = tag.find(".group-ip input").on('change keyup', () => update_category_inputs[index]());
const input_uid = tag.find(".group-unique-id input").on('change keyup', () => update_category_inputs[index]());
const input_hwid = tag.find(".group-hwid input").on('change keyup', () => update_category_inputs[index]());
const input_reason = tag.find(".group-reason textarea").on('change keyup', () => update_category_inputs[index]());
//const input_global = tag.find(".group-global input");
const input_duration_value = tag.find(".group-duration input").on('change keyup', () => update_category_inputs[index]());
const input_duration_type = tag.find(".group-duration select").on('change keyup', () => update_category_inputs[index]());
const tooltip_duration_max = tag.find(".tooltip-max-time a.max");
update_category_inputs[index] = () => {
let _criteria_set = false;
let _input_invalid = false;
{
//TODO: Check if in regex mode or not
const value = input_name.val() as string || "";
if(value.length > 255) {
_input_invalid = true;
input_name.firstParent(".input-boxed").addClass("is-invalid");
} else {
_criteria_set = _criteria_set || !!value;
input_name.firstParent(".input-boxed").removeClass("is-invalid");
}
}
2019-09-12 23:59:35 +02:00
{
//TODO: Check if in regex mode or not
const value = input_ip.val() as string || "";
if(value.length > 255) {
_input_invalid = true;
input_ip.firstParent(".input-boxed").addClass("is-invalid");
} else {
_criteria_set = _criteria_set || !!value;
input_ip.firstParent(".input-boxed").removeClass("is-invalid");
}
}
2019-09-12 23:59:35 +02:00
{
const value = input_uid.val() as string || "";
try {
if(value && atob(value).length != 20) throw "";
_criteria_set = _criteria_set || !!value;
input_uid.firstParent(".input-boxed").removeClass("is-invalid");
} catch(e) {
_input_invalid = true;
input_uid.firstParent(".input-boxed").addClass("is-invalid");
}
}
2019-09-12 23:59:35 +02:00
{
const value = input_hwid.val() as string || "";
if(value.length > 255) {
_input_invalid = true;
input_hwid.firstParent(".input-boxed").addClass("is-invalid");
} else {
_criteria_set = _criteria_set || !!value;
input_hwid.firstParent(".input-boxed").removeClass("is-invalid");
}
}
2019-09-12 23:59:35 +02:00
{
const value = input_reason.val() as string || "";
if(value.length > 512) {
_input_invalid = true;
input_reason.firstParent(".input-boxed").addClass("is-invalid");
} else {
input_reason.firstParent(".input-boxed").removeClass("is-invalid");
}
}
2019-09-12 23:59:35 +02:00
{
const type = input_duration_type.val() as string;
const value = parseInt(input_duration_value.val() as string);
const disabled = input_duration_type.prop("disabled");
input_duration_value.prop("disabled", type === "perm" || disabled).firstParent(".input-boxed").toggleClass("disabled", type === "perm" || disabled);
if(type !== "perm") {
if(input_duration_value.attr("x-saved-value")) {
input_duration_value.val(parseInt(input_duration_value.attr("x-saved-value")));
input_duration_value.attr("x-saved-value", null);
}
const selected_option = input_duration_type.find("option[value='" + type + "']");
const max = parseInt(selected_option.attr("duration-max"));
input_duration_value.attr("max", max);
if((value > max && max != -1) || value < 1) {
_input_invalid = true;
input_duration_value.firstParent(".input-boxed").addClass("is-invalid");
} else {
input_duration_value.firstParent(".input-boxed").removeClass("is-invalid");
}
if(max != -1)
tooltip_duration_max.html(tr("You're allowed to ban a maximum of ") + "<b>" + max + " " + duration_data[type][max == 1 ? "1-text" : "text"] + "</b>");
else
tooltip_duration_max.html(tr("You're allowed to ban <b>permanent</b>."));
} else {
if(value && !Number.isNaN(value))
input_duration_value.attr("x-saved-value", value);
input_duration_value.attr("placeholder", tr("for ever")).val(null);
tooltip_duration_max.html(tr("You're allowed to ban <b>permanent</b>."));
}
}
2019-09-12 23:59:35 +02:00
button_apply.prop("disabled", !(button_apply_state[button_apply_state_index] = _criteria_set && !_input_invalid));
};
2019-09-12 23:59:35 +02:00
/* initialize ban time */
controller.max_bantime().catch(error => { /* TODO: Error handling? */ return 0; }).then(max_time => {
let unlimited = max_time == 0 || max_time == -1;
if(unlimited) max_time = 0;
for(const value of Object.keys(duration_data)) {
input_duration_type.find("option[value='" + value + "']")
.prop("disabled", !unlimited && max_time >= duration_data[value].scale)
.attr("duration-scale", duration_data[value].scale)
.attr("duration-max", unlimited ? -1 : Math.floor(max_time / duration_data[value].scale));
}
input_duration_type.find("option[value='perm']")
.prop("disabled", !unlimited)
.attr("duration-scale", 0)
.attr("duration-max", -1);
});
};
2019-09-12 23:59:35 +02:00
initialize_fields(container_add, 0);
initialize_fields(container_edit, 1);
/* the edit "handler" */
{
const tag = container_edit;
const input_name = tag.find(".group-name input");
const input_ip = tag.find(".group-ip input");
const input_interpret = tag.find(".group-interpret select");
const input_uid = tag.find(".group-unique-id input");
const input_hwid = tag.find(".group-hwid input");
const input_reason = tag.find(".group-reason textarea");
const input_global = tag.find(".group-global input");
const input_duration_value = tag.find(".group-duration input");
const input_duration_type = tag.find(".group-duration select");
const tooltip_duration_detailed = tag.find(".tooltip-max-time a.detailed");
const label_enforcement_count = tag.find(".group-enforcements .value a");
const button_enforcement_list = tag.find(".button-enforcement-list");
const container_creator = tag.find(".group-creator .value");
update_edit_window = (switch_to: boolean) => {
category_edit.toggleClass("disabled", !selected_ban);
const editable = selected_ban && selected_ban.server_id === 0 ? permission_edit[1] : permission_edit[0];
input_name.val(selected_ban ? selected_ban.name : null).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_ip.val(selected_ban ? selected_ban.ip : null).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_uid.val(selected_ban ? selected_ban.unique_id : null).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_hwid.val(selected_ban ? selected_ban.hardware_id : null).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_reason.val(selected_ban ? selected_ban.reason : null).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_interpret.find("option").eq(selected_ban && typeof(selected_ban.name_type) === "number" ? selected_ban.name_type : 2).prop("selected", true).prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
label_enforcement_count.text((selected_ban ? selected_ban.enforcements : 0) || 0);
button_enforcement_list.prop("disabled", !selected_ban || selected_ban.enforcements == 0);
input_global.prop("checked", selected_ban && selected_ban.server_id == 0);
input_duration_type.prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
input_duration_value.prop("disabled", !editable).firstParent(".input-boxed").toggleClass("disabled", !editable);
if(selected_ban) {
if(selected_ban.timestamp_expire > selected_ban.timestamp_created) {
const duration = Math.ceil((selected_ban.timestamp_expire - selected_ban.timestamp_created) / 1000);
const periods = Object.keys(duration_data);
let index;
for(index = 0; index < periods.length; index++) {
if(duration_data[periods[index]].scale > duration + 1 || ((duration + 1) % duration_data[periods[index]].scale) > 1.9)
break;
}
if(index > 0) index--;
input_duration_type.find("option[value='" + periods[index] + "']").prop("selected", true);
input_duration_value.val(Math.ceil(duration / duration_data[periods[index]].scale));
tooltip_duration_detailed.text($.spawn("div").append(...MessageHelper.formatMessage(tr("The ban lasts for exact {}."), MessageHelper.format_time(duration * 1000, "never"))).text());
} else {
tooltip_duration_detailed.text(tr("The ban is forever."));
input_duration_value.attr("placeholder", tr("for ever")).val(null).prop('disabled', true);
input_duration_type.find("option[value='perm']").prop("selected", true);
}
}
2019-09-12 23:59:35 +02:00
container_creator.empty();
if(selected_ban) {
container_creator.append(
htmltags.generate_client_object({
client_id: 0,
client_unique_id: selected_ban.invoker_unique_id,
client_name: selected_ban.invoker_name,
add_braces: false
})
);
}
2019-09-12 23:59:35 +02:00
if(switch_to)
category_edit.trigger('click');
};
2019-09-12 23:59:35 +02:00
button_apply.on('click', event => {
if (!button_apply_state[1] || button_apply_state_index != 1) return;
const data = {banid: selected_ban.banid};
if(input_ip.val() != selected_ban.ip)
data["ip"] = input_ip.val();
2019-09-12 23:59:35 +02:00
if(input_name.val() != selected_ban.name)
data["name"] = input_name.val();
if(input_uid.val() != selected_ban.unique_id)
data["uid"] = input_uid.val();
if(input_hwid.val() != selected_ban.hardware_id)
data["hwid"] = input_hwid.val();
if(input_reason.val() != selected_ban.reason)
data["banreason"] = input_reason.val();
if(input_reason.val() != selected_ban.reason)
data["reason"] = input_reason.val();
const duration = input_duration_type.val() === "perm" ? 0 : (1000 * parseInt(input_duration_type.find("option[value='" + input_duration_type.val() + "']").attr("duration-scale")) * parseInt(input_duration_value.val() as string));
if(selected_ban.timestamp_expire > 0 ? (selected_ban.timestamp_expire - selected_ban.timestamp_created != duration) : duration != 0)
data["time"] = Math.floor(duration / 1000);
controller.edit_ban(data).then(() => {
update_banlist(selected_ban ? selected_ban.banid : undefined);
selected_ban = undefined;
update_edit_window(false);
createInfoModal(tr("Ban successfully edited"), tr("Your ban has been successfully edited.")).open();
}).catch(error => {
log.error(LogCategory.CLIENT, tr("Failed to edited ban: %o"), error);
if(error instanceof CommandResult)
error = error.id === ErrorID.PERMISSION_ERROR ? "no permissions" : error.extra_message || error.message;
createErrorModal(tr("Failed to edited ban"), MessageHelper.formatMessage(tr("Failed to edited ban. {:br:}Error: {}"), error)).open();
});
});
2019-09-12 23:59:35 +02:00
button_enforcement_list.on('click', () => {
update_triggerlist();
show_triggerlist();
});
2019-09-12 23:59:35 +02:00
}
/* the create "handler" */
{
const tag = container_add;
const input_name = tag.find(".group-name input");
const input_ip = tag.find(".group-ip input");
const input_interpret = tag.find(".group-interpret select");
const input_uid = tag.find(".group-unique-id input");
const input_hwid = tag.find(".group-hwid input");
const input_reason = tag.find(".group-reason textarea");
const input_global = tag.find(".group-global input");
const input_duration_value = tag.find(".group-duration input");
const input_duration_type = tag.find(".group-duration select");
button_apply.on('click', event => {
if(!button_apply_state[0] || button_apply_state_index != 0) return;
const data: BanEntry = {
banid: 0,
enforcements: 0,
} as any;
if(input_global.prop('checked'))
data.server_id = 0;
if(input_ip.val())
data.ip = input_ip.val() as any;
if(input_name.val())
data.name = input_name.val() as any;
if(input_uid.val())
data.unique_id = input_uid.val() as any;
if(input_hwid.val())
data.hardware_id = input_hwid.val() as any;
if(input_reason.val())
data.reason = input_reason.val() as any;
data.timestamp_created = Date.now();
data.timestamp_expire = input_duration_type.val() === "perm" ? 0 : (data.timestamp_created + 1000 * parseInt(input_duration_type.find("option[value='" + input_duration_type.val() + "']").attr("duration-scale")) * parseInt(input_duration_value.val() as string));
//TODO: input_interpret (Currently not supported by TeaSpeak)
controller.add_ban(data).then(() => {
input_name.val(null);
input_ip.val(null);
input_uid.val(null);
input_hwid.val(null);
input_reason.val(null);
input_duration_value.val(1);
update_banlist();
createInfoModal(tr("Ban successfully added"), tr("Your ban has been successfully added.")).open();
}).catch(error => {
log.error(LogCategory.CLIENT, tr("Failed to add ban: %o"), error);
if(error instanceof CommandResult)
error = error.id === ErrorID.PERMISSION_ERROR ? "no permissions" : error.extra_message || error.message;
createErrorModal(tr("Failed to add ban"), MessageHelper.formatMessage(tr("Failed to add ban. {:br:}Error: {}"), error)).open();
});
});
}
/* the banlist filter */
{
const input_filter = container_ban.find(".container-filter input").on('change keyup', () => update_ban_filter());
const option_show_own = container_ban.find(".option-show-own").on('change keyup', () => update_ban_filter());
const option_hightlight_own = container_ban.find(".option-highlight-own").on('change keyup', () => update_ban_filter());
update_ban_filter = () => {
const text = (input_filter.val() as string || "").toLowerCase();
const flag_show_own = option_show_own.prop('checked');
const flag_hightlight_own = option_hightlight_own.prop('checked');
let count = 0;
for(const entry of callback_ban_filter)
if(entry(text, flag_show_own, flag_hightlight_own))
count++;
if(callback_ban_filter.length != 0) {
if(count > 0)
container_ban_entries_empty.hide();
else
container_ban_entries_empty.show().find("a").text(tr("No bans found"));
}
};
}
/* the trigger list filter */
{
const input_filter = container_trigger.find(".container-filter input").on('change keyup', () => update_trigger_filter());
const option_hightlight_cause = container_trigger.find(".option-highlight-cause").on('change keyup', () => update_trigger_filter());
const button_close = container_trigger.find(".container-close");
update_trigger_filter = () => {
const text = (input_filter.val() as string || "").toLowerCase();
let count = 0;
for(const entry of callback_trigger_filter)
if(entry(text))
count++;
if(callback_trigger_filter.length != 0) {
if(count > 0)
container_trigger_entries_empty.hide();
else
container_trigger_entries_empty.show().find("a").text(tr("No trigger events found"));
}
container_trigger.find(".container-list").toggleClass('highlight', option_hightlight_cause.prop('checked'));
};
button_close.on('click', () => container_trigger.hide());
}
template.find(".button-refresh-banlist").on('click', event => update_banlist(selected_ban ? selected_ban.banid : undefined));
template.find(".button-refresh-triggerlist").on('click', event => update_triggerlist());
/* initialize */
category_add.trigger('click');
update_edit_window(false);
update_banlist();
tooltip(template);
return template.children();
}
}
2019-09-12 23:59:35 +02:00
//container-triggerlist