diff --git a/js/client.ts b/js/client.ts
index f2d5b862..fa8e0ee4 100644
--- a/js/client.ts
+++ b/js/client.ts
@@ -8,7 +8,7 @@
///
///
///
-///
+///
enum DisconnectReason {
REQUESTED,
diff --git a/js/load.ts b/js/load.ts
index a5199828..c7d56383 100644
--- a/js/load.ts
+++ b/js/load.ts
@@ -152,7 +152,9 @@ function loadDebug() {
"js/ui/client.js",
"js/ui/server.js",
"js/ui/view.js",
- "js/ui/ControlBar.js",
+
+ "js/ui/frames/SelectedItemInfo.js",
+ "js/ui/frames/ControlBar.js",
//Load permissions
"js/permission/PermissionManager.js",
@@ -176,7 +178,6 @@ function loadDebug() {
"js/FileManager.js",
"js/client.js",
"js/chat.js",
- "js/ui/frames/SelectedItemInfo.js",
"js/Identity.js"
])).then(() => {
awaitLoad(loadScripts(["js/main.js"])).then(() => {
diff --git a/js/main.ts b/js/main.ts
index c9f41170..eeb2502b 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -37,7 +37,6 @@ function main() {
chat = new ChatBox($("#chat"));
globalClient.setup();
- //globalClient.startConnection("localhost:19974"); //TODO remove only for testing
if(!settings.static(Settings.KEY_DISABLE_UNLOAD_DIALOG, false)) {
diff --git a/js/permission/PermissionManager.ts b/js/permission/PermissionManager.ts
index 383fda0b..e5b5342b 100644
--- a/js/permission/PermissionManager.ts
+++ b/js/permission/PermissionManager.ts
@@ -293,7 +293,7 @@ class PermissionInfo {
description: string;
}
-class GrantedPermission {
+class PermissionValue {
readonly type: PermissionInfo;
value: number;
@@ -303,10 +303,8 @@ class GrantedPermission {
}
granted(requiredValue: number, required: boolean = true) : boolean {
- let result = false;
- if(this.value == -2)
- result = !required;
- result = this.value == -1 || this.value >= requiredValue;
+ let result;
+ result = this.value == -1 || this.value >= requiredValue || (this.value == -2 && requiredValue == -2 && !required);
log.trace(LogCategory.PERMISSIONS, "Test needed required: %o | %i | %o => " + result , this, requiredValue, required);
return result;
}
@@ -316,7 +314,7 @@ class GrantedPermission {
}
}
-class NeededGrantedPermission extends GrantedPermission {
+class NeededPermissionValue extends PermissionValue {
changeListener: ((newValue: number) => void)[] = [];
constructor(type, value) {
@@ -324,11 +322,20 @@ class NeededGrantedPermission extends GrantedPermission {
}
}
+class ChannelPermissionRequest {
+ requested: number;
+ channel_id: number;
+ callback_success: ((_: PermissionValue[]) => any)[] = [];
+ callback_error: ((_: any) => any)[] = [];
+}
+
class PermissionManager {
readonly handle: TSClient;
permissionList: PermissionInfo[] = [];
- neededPermissions: NeededGrantedPermission[] = [];
+ neededPermissions: NeededPermissionValue[] = [];
+
+ requests_channel_permissions: ChannelPermissionRequest[] = [];
initializedListener: ((initialized: boolean) => void)[] = [];
private _cacheNeededPermissions: any;
@@ -338,6 +345,7 @@ class PermissionManager {
this.handle.serverConnection.commandHandler["notifyclientneededpermissions"] = this.onNeededPermissions.bind(this);
this.handle.serverConnection.commandHandler["notifypermissionlist"] = this.onPermissionList.bind(this);
+ this.handle.serverConnection.commandHandler["notifychannelpermlist"] = this.onChannelPermList.bind(this);
}
initialized() : boolean {
@@ -384,7 +392,7 @@ class PermissionManager {
let group = log.group(log.LogType.TRACE, LogCategory.PERMISSIONS, "Got " + json.length + " needed permissions.");
for(let e of json) {
- let entry: NeededGrantedPermission = undefined;
+ let entry: NeededPermissionValue = undefined;
for(let p of copy) {
if(p.type.id == e["permid"]) {
entry = p;
@@ -395,7 +403,7 @@ class PermissionManager {
if(!entry) {
let info = this.resolveInfo(e["permid"]);
if(info) {
- entry = new NeededGrantedPermission(info, -2);
+ entry = new NeededPermissionValue(info, -2);
this.neededPermissions.push(entry);
} else {
log.warn(LogCategory.PERMISSIONS, "Could not resolve perm for id %s (%o|%o)", e["permid"], e, info);
@@ -420,6 +428,32 @@ class PermissionManager {
}
}
+ private onChannelPermList(json) {
+ let permissions: PermissionValue[] = [];
+ let channelId: number = parseInt(json[0]["cid"]);
+ for(let element of json) {
+ let permission = this.resolveInfo(element["permid"]);
+ //TODO granted skipped and negated permissions
+ if(!permission) {
+ log.error(LogCategory.PERMISSIONS, "Failed to parse channel permission with id %o", element["permid"]);
+ continue;
+ }
+
+ permissions.push(new PermissionValue(permission, element["permvalue"]));
+ }
+
+ log.debug(LogCategory.PERMISSIONS, "Got channel permissions for channel %o", channelId);
+ for(let element of this.requests_channel_permissions) {
+ if(element.channel_id == channelId) {
+ for(let l of element.callback_success)
+ l(permissions);
+ this.requests_channel_permissions.remove(element);
+ return;
+ }
+ }
+ log.debug(LogCategory.PERMISSIONS, "Missing channel permission handle for requested channel id %o", channelId);
+ }
+
resolveInfo?(key: number | string | PermissionType) : PermissionInfo {
for(let perm of this.permissionList)
if(perm.id == key || perm.name == key)
@@ -427,7 +461,27 @@ class PermissionManager {
return undefined;
}
- neededPermission(key: number | string | PermissionType | PermissionInfo) : GrantedPermission {
+ requestChannelPermissions(channelId: number) : Promise {
+ return new Promise((resolve, reject) => {
+ let request: ChannelPermissionRequest;
+ for(let element of this.requests_channel_permissions)
+ if(element.requested + 1000 < Date.now() && request.channel_id == channelId) {
+ request = element;
+ break;
+ }
+ if(!request) {
+ request = new ChannelPermissionRequest();
+ request.requested = Date.now();
+ request.channel_id = channelId;
+ this.handle.serverConnection.sendCommand("channelpermlist", {"cid": channelId});
+ this.requests_channel_permissions.push(request);
+ }
+ request.callback_error.push(reject);
+ request.callback_success.push(resolve);
+ });
+ }
+
+ neededPermission(key: number | string | PermissionType | PermissionInfo) : PermissionValue {
for(let perm of this.neededPermissions)
if(perm.type.id == key || perm.type.name == key || perm.type == key)
return perm;
@@ -437,7 +491,7 @@ class PermissionManager {
log.warn(LogCategory.PERMISSIONS, "Requested needed permission with invalid key! (%o)", key);
return undefined;
}
- let result = new NeededGrantedPermission(info, -2);
+ let result = new NeededPermissionValue(info, -2);
this.neededPermissions.push(result);
return result;
diff --git a/js/ui/channel.ts b/js/ui/channel.ts
index d8868209..d5809e3a 100644
--- a/js/ui/channel.ts
+++ b/js/ui/channel.ts
@@ -292,9 +292,7 @@ class ChannelEntry {
type: MenuEntryType.ENTRY,
icon: "client-channel_switch",
name: "Switch to channel",
- callback: () => {
- this.joinChannel();
- }
+ callback: () => this.joinChannel()
},
MenuEntry.HR(),
{
@@ -303,10 +301,13 @@ class ChannelEntry {
name: "Edit channel",
invalidPermission: !channelModify,
callback: () => {
- Modals.createChannelModal(this, undefined, (changes?: ChannelProperties) => {
+ Modals.createChannelModal(this, undefined, this.channelTree.client.permissions, (changes?: ChannelProperties) => {
if(!changes) return;
changes["cid"] = this.channelId;
+ this.channelTree.client.serverConnection.sendCommand("channeledit", changes);
log.info(LogCategory.CHANNEL, "Changed channel properties of channel %s: %o", this.channelName(), changes);
+ }, permissions => {
+ //TODO
});
}
},
diff --git a/js/ui/ControlBar.ts b/js/ui/frames/ControlBar.ts
similarity index 98%
rename from js/ui/ControlBar.ts
rename to js/ui/frames/ControlBar.ts
index a7f31d22..e9bc3ec7 100644
--- a/js/ui/ControlBar.ts
+++ b/js/ui/frames/ControlBar.ts
@@ -1,5 +1,5 @@
-///
-///
+///
+///
/*
client_output_hardware Value: '1'
client_output_muted Value: '0'
diff --git a/js/ui/modal/ModalCreateChannel.ts b/js/ui/modal/ModalCreateChannel.ts
index d48845ac..1dc2a6dc 100644
--- a/js/ui/modal/ModalCreateChannel.ts
+++ b/js/ui/modal/ModalCreateChannel.ts
@@ -1,7 +1,7 @@
///
namespace Modals {
- export function createChannelModal(channel: ChannelEntry | undefined, parent: ChannelEntry | undefined, callback: (ChannelProperties?: ChannelProperties) => void) {
+ export function createChannelModal(channel: ChannelEntry | undefined, parent: ChannelEntry | undefined, permissions: PermissionManager, callback: (ChannelProperties?: ChannelProperties) => void, callback_permission: (_: PermissionValue[]) => any) {
let properties: ChannelProperties = { } as ChannelProperties; //The changes properties
const modal = createModal({
header: channel ? "Edit channel" : "Create channel",
@@ -32,10 +32,27 @@ namespace Modals {
applyGeneralListener(properties, modal.htmlTag.find(".channel_general_properties"), modal.htmlTag.find(".button_ok"), !channel);
applyStandardListener(properties, modal.htmlTag.find(".settings_standard"), modal.htmlTag.find(".button_ok"), parent, !channel);
+ applyPermissionListener(properties, modal.htmlTag.find(".settings_permissions"), modal.htmlTag.find(".button_ok"), permissions, channel);
+ let updated: PermissionValue[] = [];
modal.htmlTag.find(".button_ok").click(() => {
+ modal.htmlTag.find(".settings_permissions").find("input[permission]").each((index, _element) => {
+ let element = $(_element);
+ if(!element.prop("changed")) return;
+ let permission = permissions.resolveInfo(element.attr("permission"));
+ if(!permission) {
+ log.error(LogCategory.PERMISSIONS, "Failed to resolve channel permission for name %o", element.attr("permission"));
+ element.prop("disabled", true);
+ return;
+ }
+
+ updated.push(new PermissionValue(permission, element.val()));
+ });
+ console.log("Updated permissions %o", updated);
+ }).click(() => {
modal.close();
- callback(properties);
+ callback(properties); //First may create the channel
+ callback_permission(updated);
});
modal.htmlTag.find(".button_cancel").click(() => {
@@ -111,7 +128,8 @@ namespace Modals {
.prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_SEMI_PERMANENT : PermissionType.B_CHANNEL_MODIFY_MAKE_SEMI_PERMANENT).granted(1));
tag.find("input[name=\"channel_type\"][value=\"perm\"]")
.prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_PERMANENT : PermissionType.B_CHANNEL_MODIFY_MAKE_PERMANENT).granted(1));
- tag.find("input[name=\"channel_type\"]:not(:disabled)").last().prop("checked", true).trigger('change');
+ if(create)
+ tag.find("input[name=\"channel_type\"]:not(:disabled)").last().prop("checked", true).trigger('change');
tag.find("input[name=\"channel_default\"]").change(function (this: HTMLInputElement) {
console.log(this.checked);
@@ -141,4 +159,51 @@ namespace Modals {
}).prop("disabled", !globalClient.permissions.neededPermission(create ? PermissionType.B_CHANNEL_CREATE_WITH_SORTORDER : PermissionType.B_CHANNEL_MODIFY_SORTORDER).granted(1));
orderTag.find("option").last().prop("selected", true);
}
+
+
+ function applyPermissionListener(properties: ChannelProperties, tag: JQuery, button: JQuery, permissions: PermissionManager, channel?: ChannelEntry) {
+ let apply_permissions = (channel_permissions: PermissionValue[]) => {
+ console.log("Got permissions: %o", channel_permissions);
+ let required_power = -2;
+ for(let cperm of channel_permissions)
+ if(cperm.type.name == PermissionType.I_CHANNEL_NEEDED_MODIFY_POWER) {
+ required_power = cperm.value;
+ return;
+ }
+
+ tag.find("input[permission]").each((index, _element) => {
+ let element = $(_element);
+ let permission = permissions.resolveInfo(element.attr("permission"));
+ if(!permission) {
+ log.error(LogCategory.PERMISSIONS, "Failed to resolve channel permission for name %o", element.attr("permission"));
+ element.prop("disabled", true);
+ return;
+ }
+
+ let old_value: number = 0;
+ element.on("click keyup", () => {
+ console.log("Permission triggered! %o", element.val() != old_value);
+ element.prop("changed", element.val() != old_value);
+ });
+
+ for(let cperm of channel_permissions)
+ if(cperm.type == permission) {
+ element.val(old_value = cperm.value);
+ return;
+ }
+ element.val(0);
+ });
+
+ if(!permissions.neededPermission(PermissionType.I_CHANNEL_MODIFY_POWER).granted(required_power, false)) {
+ tag.find("input[permission]").prop("enabled", false); //No permissions
+ }
+ };
+
+ if(channel) {
+ permissions.requestChannelPermissions(channel.getChannelId()).then(apply_permissions).catch((error) => {
+ tag.find("input[permission]").prop("enabled", false);
+ console.log(error);
+ });
+ } else apply_permissions([]);
+ }
}
\ No newline at end of file
diff --git a/js/ui/view.ts b/js/ui/view.ts
index 69dc69cb..c3b0b3dd 100644
--- a/js/ui/view.ts
+++ b/js/ui/view.ts
@@ -255,11 +255,13 @@ class ChannelTree {
}
spawnCreateChannel(parent?: ChannelEntry) {
- Modals.createChannelModal(undefined, parent, (properties?: ChannelProperties) => {
+ Modals.createChannelModal(undefined, parent, this.client.permissions, (properties?: ChannelProperties) => {
if(!properties) return;
properties["cpid"] = parent ? parent.channelId : 0;
log.debug(LogCategory.CHANNEL, "Creating new channel with properties: %o", properties);
this.client.serverConnection.sendCommand("channelcreate", properties);
+ }, permissions => {
+ //TODO
});
}
}
\ No newline at end of file
diff --git a/templates.html b/templates.html
index 34c6c44f..1b06579f 100644
--- a/templates.html
+++ b/templates.html
@@ -45,9 +45,9 @@