diff --git a/lib/ChannelPermissions.js b/lib/ChannelPermissions.js new file mode 100644 index 000000000..bbc8545db --- /dev/null +++ b/lib/ChannelPermissions.js @@ -0,0 +1,182 @@ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var ChannelPermissions = (function () { + function ChannelPermissions(data, channel) { + _classCallCheck(this, ChannelPermissions); + + var self = this; + + function getBit(x) { + return (self.packed >>> x & 1) === 1; + } + + this.type = data.type; //either member or role + this.id = data.id; + + if (this.type === "member") { + this.packed = channel.server.getMember("id", data.id).evalPerms.packed; + } else { + this.packed = channel.server.getRole(data.id).packed; + } + + this.packed = this.packed & ~data.deny; + this.packed = this.packed | data.allow; + + this.deny = data.deny; + this.allow = data.allow; + } + + _createClass(ChannelPermissions, [{ + key: "getBit", + value: function getBit(x) { + return (this.packed >>> x & 1) === 1; + } + }, { + key: "setBit", + value: function setBit() {} + }, { + key: "createInstantInvite", + get: function get() { + return this.getBit(0); + }, + set: function set(val) { + this.setBit(0, val); + } + }, { + key: "manageRoles", + get: function get() { + return this.getBit(3); + }, + set: function set(val) { + this.setBit(3, val); + } + }, { + key: "manageChannels", + get: function get() { + return this.getBit(4); + }, + set: function set(val) { + this.setBit(4, val); + } + }, { + key: "readMessages", + get: function get() { + return this.getBit(10); + }, + set: function set(val) { + this.setBit(10, val); + } + }, { + key: "sendMessages", + get: function get() { + return this.getBit(11); + }, + set: function set(val) { + this.setBit(11, val); + } + }, { + key: "sendTTSMessages", + get: function get() { + return this.getBit(12); + }, + set: function set(val) { + this.setBit(12, val); + } + }, { + key: "manageMessages", + get: function get() { + return this.getBit(13); + }, + set: function set(val) { + this.setBit(13, val); + } + }, { + key: "embedLinks", + get: function get() { + return this.getBit(14); + }, + set: function set(val) { + this.setBit(14, val); + } + }, { + key: "attachFiles", + get: function get() { + return this.getBit(15); + }, + set: function set(val) { + this.setBit(15, val); + } + }, { + key: "readMessageHistory", + get: function get() { + return this.getBit(16); + }, + set: function set(val) { + this.setBit(16, val); + } + }, { + key: "mentionEveryone", + get: function get() { + return this.getBit(17); + }, + set: function set(val) { + this.setBit(17, val); + } + }, { + key: "voiceConnect", + get: function get() { + return this.getBit(20); + }, + set: function set(val) { + this.setBit(20, val); + } + }, { + key: "voiceSpeak", + get: function get() { + return this.getBit(21); + }, + set: function set(val) { + this.setBit(21, val); + } + }, { + key: "voiceMuteMembers", + get: function get() { + return this.getBit(22); + }, + set: function set(val) { + this.setBit(22, val); + } + }, { + key: "voiceDeafenMembers", + get: function get() { + return this.getBit(23); + }, + set: function set(val) { + this.setBit(23, val); + } + }, { + key: "voiceMoveMembers", + get: function get() { + return this.getBit(24); + }, + set: function set(val) { + this.setBit(24, val); + } + }, { + key: "voiceUseVoiceActivation", + get: function get() { + return this.getBit(25); + }, + set: function set(val) { + this.setBit(25, val); + } + }]); + + return ChannelPermissions; +})(); + +module.exports = ChannelPermissions; \ No newline at end of file diff --git a/lib/Client.js b/lib/Client.js index 526ea0d77..b4f54294a 100644 --- a/lib/Client.js +++ b/lib/Client.js @@ -1031,11 +1031,7 @@ var Client = (function () { var user = self.addUser(data.user); //if for whatever reason it doesn't exist.. - if (! ~server.members.indexOf(user)) { - server.members.push(user); - } - - self.trigger("serverNewMember", user, server); + self.trigger("serverNewMember", server.addMember(user, data.roles), server); } break; @@ -1048,9 +1044,7 @@ var Client = (function () { var user = self.addUser(data.user); //if for whatever reason it doesn't exist.. - if (~server.members.indexOf(user)) { - server.members.splice(server.members.indexOf(user), 1); - } + server.removeMember("id", user.id); self.trigger("serverRemoveMember", user, server); } @@ -1140,6 +1134,27 @@ var Client = (function () { break; + case "GUILD_ROLE_DELETE": + + var server = self.getServer("id", data.guild_id); + var role = server.getRole(data.role_id); + + self.trigger("serverRoleDelete", server, role); + + server.removeRole(role.id); + + break; + + case "GUILD_ROLE_UPDATE": + + var server = self.getServer("id", data.guild_id); + var role = server.getRole(data.role.id); + var newRole = server.updateRole(data.role); + + self.trigger("serverRoleUpdate", server, role, newRole); + + break; + default: self.debug("received unknown packet"); self.trigger("unknown", dat); diff --git a/lib/EvaluatedPermissions.js b/lib/EvaluatedPermissions.js new file mode 100644 index 000000000..b441500cf --- /dev/null +++ b/lib/EvaluatedPermissions.js @@ -0,0 +1,172 @@ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var EvaluatedPermissions = (function () { + function EvaluatedPermissions(data) { + _classCallCheck(this, EvaluatedPermissions); + + var self = this; + + function getBit(x) { + if ((self.packed >>> 3 & 1) === 1) { + return true; + } + return (self.packed >>> x & 1) === 1; + } + + this.packed = data; + } + + _createClass(EvaluatedPermissions, [{ + key: "getBit", + value: function getBit(x) { + return (this.packed >>> x & 1) === 1; + } + }, { + key: "setBit", + value: function setBit() {} + }, { + key: "createInstantInvite", + get: function get() { + return this.getBit(0); + }, + set: function set(val) { + this.setBit(0, val); + } + }, { + key: "manageRoles", + get: function get() { + return this.getBit(3); + }, + set: function set(val) { + this.setBit(3, val); + } + }, { + key: "manageChannels", + get: function get() { + return this.getBit(4); + }, + set: function set(val) { + this.setBit(4, val); + } + }, { + key: "readMessages", + get: function get() { + return this.getBit(10); + }, + set: function set(val) { + this.setBit(10, val); + } + }, { + key: "sendMessages", + get: function get() { + return this.getBit(11); + }, + set: function set(val) { + this.setBit(11, val); + } + }, { + key: "sendTTSMessages", + get: function get() { + return this.getBit(12); + }, + set: function set(val) { + this.setBit(12, val); + } + }, { + key: "manageMessages", + get: function get() { + return this.getBit(13); + }, + set: function set(val) { + this.setBit(13, val); + } + }, { + key: "embedLinks", + get: function get() { + return this.getBit(14); + }, + set: function set(val) { + this.setBit(14, val); + } + }, { + key: "attachFiles", + get: function get() { + return this.getBit(15); + }, + set: function set(val) { + this.setBit(15, val); + } + }, { + key: "readMessageHistory", + get: function get() { + return this.getBit(16); + }, + set: function set(val) { + this.setBit(16, val); + } + }, { + key: "mentionEveryone", + get: function get() { + return this.getBit(17); + }, + set: function set(val) { + this.setBit(17, val); + } + }, { + key: "voiceConnect", + get: function get() { + return this.getBit(20); + }, + set: function set(val) { + this.setBit(20, val); + } + }, { + key: "voiceSpeak", + get: function get() { + return this.getBit(21); + }, + set: function set(val) { + this.setBit(21, val); + } + }, { + key: "voiceMuteMembers", + get: function get() { + return this.getBit(22); + }, + set: function set(val) { + this.setBit(22, val); + } + }, { + key: "voiceDeafenMembers", + get: function get() { + return this.getBit(23); + }, + set: function set(val) { + this.setBit(23, val); + } + }, { + key: "voiceMoveMembers", + get: function get() { + return this.getBit(24); + }, + set: function set(val) { + this.setBit(24, val); + } + }, { + key: "voiceUseVoiceActivation", + get: function get() { + return this.getBit(25); + }, + set: function set(val) { + this.setBit(25, val); + } + }]); + + return EvaluatedPermissions; +})(); + +module.exports = EvaluatedPermissions; \ No newline at end of file diff --git a/lib/Member.js b/lib/Member.js index 7d7b03f1a..ba29467db 100644 --- a/lib/Member.js +++ b/lib/Member.js @@ -1,5 +1,7 @@ "use strict"; +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } @@ -7,15 +9,217 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Cons function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var User = require("./user.js"); +var ServerPermissions = require("./ServerPermissions.js"); +var EvaluatedPermissions = require("./EvaluatedPermissions.js"); var Member = (function (_User) { _inherits(Member, _User); - function Member(data) { + function Member(user, server, roles) { _classCallCheck(this, Member); - _get(Object.getPrototypeOf(Member.prototype), "constructor", this).call(this, data); + _get(Object.getPrototypeOf(Member.prototype), "constructor", this).call(this, user); // should work, we are basically creating a Member that has the same properties as user and a few more + this.server = server; + this.rawRoles = roles; } + _createClass(Member, [{ + key: "permissionsIn", + value: function permissionsIn(channel) { + + if (channel.server.ownerID === this.id) { + return new EvaluatedPermissions(4294967295); //all perms + } + + var affectingOverwrites = []; + var affectingMemberOverwrites = []; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = channel.roles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var overwrite = _step.value; + + if (overwrite.id === this.id && overwrite.type === "member") { + affectingMemberOverwrites.push(overwrite); + } else if (this.rawRoles.indexOf(overwrite.id) !== -1) { + affectingOverwrites.push(overwrite); + } + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator["return"]) { + _iterator["return"](); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = affectingOverwrites[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var perm = _step2.value; + + console.log("hey", perm.attachFiles); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2["return"]) { + _iterator2["return"](); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + if (affectingOverwrites.length === 0 && affectingMemberOverwrites.length === 0) { + return new EvaluatedPermissions(this.evalPerms.packed); + } + + var finalPacked = affectingOverwrites.length !== 0 ? affectingOverwrites[0].packed : affectingMemberOverwrites[0].packed; + + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = affectingOverwrites[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var overwrite = _step3.value; + + finalPacked = finalPacked & ~overwrite.deny; + finalPacked = finalPacked | overwrite.allow; + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3["return"]) { + _iterator3["return"](); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = affectingMemberOverwrites[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + var overwrite = _step4.value; + + finalPacked = finalPacked & ~overwrite.deny; + finalPacked = finalPacked | overwrite.allow; + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4["return"]) { + _iterator4["return"](); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + + return new EvaluatedPermissions(finalPacked); + } + }, { + key: "roles", + get: function get() { + + var ufRoles = [this.server.getRole(this.server.id)]; + + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = this.rawRoles[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + var rawRole = _step5.value; + + ufRoles.push(this.server.getRole(rawRole)); + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5["return"]) { + _iterator5["return"](); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + return ufRoles; + } + }, { + key: "evalPerms", + get: function get() { + var basePerms = this.roles, + //cache roles as it can be slightly expensive + basePerm = basePerms[0].packed; + + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = basePerms[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + var perm = _step6.value; + + basePerm = basePerm | perm.packed; + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6["return"]) { + _iterator6["return"](); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + return new ServerPermissions({ + permissions: basePerm + }); + } + }]); + return Member; -})(User); \ No newline at end of file +})(User); + +module.exports = Member; \ No newline at end of file diff --git a/lib/ServerPermissions.js b/lib/ServerPermissions.js new file mode 100644 index 000000000..73148ca06 --- /dev/null +++ b/lib/ServerPermissions.js @@ -0,0 +1,202 @@ +"use strict"; + +var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var ServerPermissions = (function () { + function ServerPermissions(data) { + _classCallCheck(this, ServerPermissions); + + var self = this; + + function getBit(x) { + return (self.packed >>> x & 1) === 1; + } + + this.packed = data.permissions; + this.name = data.name; + this.id = data.id; + } + + _createClass(ServerPermissions, [{ + key: "getBit", + value: function getBit(x) { + return (this.packed >>> x & 1) === 1; + } + }, { + key: "setBit", + value: function setBit() { + //dummy function for now + } + }, { + key: "toString", + value: function toString() { + return this.name; + } + }, { + key: "createInstantInvite", + get: function get() { + return this.getBit(0); + }, + set: function set(val) { + this.setBit(0, val); + } + }, { + key: "banMembers", + get: function get() { + return this.getBit(1); + }, + set: function set(val) { + this.setBit(1, val); + } + }, { + key: "kickMembers", + get: function get() { + return this.getBit(2); + }, + set: function set(val) { + this.setBit(2, val); + } + }, { + key: "manageRoles", + get: function get() { + return this.getBit(3); + }, + set: function set(val) { + this.setBit(3, val); + } + }, { + key: "manageChannels", + get: function get() { + return this.getBit(4); + }, + set: function set(val) { + this.setBit(4, val); + } + }, { + key: "manageServer", + get: function get() { + return this.getBit(5); + }, + set: function set(val) { + this.setBit(5, val); + } + }, { + key: "readMessages", + get: function get() { + return this.getBit(10); + }, + set: function set(val) { + this.setBit(10, val); + } + }, { + key: "sendMessages", + get: function get() { + return this.getBit(11); + }, + set: function set(val) { + this.setBit(11, val); + } + }, { + key: "sendTTSMessages", + get: function get() { + return this.getBit(12); + }, + set: function set(val) { + this.setBit(12, val); + } + }, { + key: "manageMessages", + get: function get() { + return this.getBit(13); + }, + set: function set(val) { + this.setBit(13, val); + } + }, { + key: "embedLinks", + get: function get() { + return this.getBit(14); + }, + set: function set(val) { + this.setBit(14, val); + } + }, { + key: "attachFiles", + get: function get() { + return this.getBit(15); + }, + set: function set(val) { + this.setBit(15, val); + } + }, { + key: "readMessageHistory", + get: function get() { + return this.getBit(16); + }, + set: function set(val) { + this.setBit(16, val); + } + }, { + key: "mentionEveryone", + get: function get() { + return this.getBit(17); + }, + set: function set(val) { + this.setBit(17, val); + } + }, { + key: "voiceConnect", + get: function get() { + return this.getBit(20); + }, + set: function set(val) { + this.setBit(20, val); + } + }, { + key: "voiceSpeak", + get: function get() { + return this.getBit(21); + }, + set: function set(val) { + this.setBit(21, val); + } + }, { + key: "voiceMuteMembers", + get: function get() { + return this.getBit(22); + }, + set: function set(val) { + this.setBit(22, val); + } + }, { + key: "voiceDeafenMembers", + get: function get() { + return this.getBit(23); + }, + set: function set(val) { + this.setBit(23, val); + } + }, { + key: "voiceMoveMembers", + get: function get() { + return this.getBit(24); + }, + set: function set(val) { + this.setBit(24, val); + } + }, { + key: "voiceUseVoiceActivation", + get: function get() { + return this.getBit(25); + }, + set: function set(val) { + this.setBit(25, val); + } + }]); + + return ServerPermissions; +})(); + +module.exports = ServerPermissions; \ No newline at end of file diff --git a/lib/channel.js b/lib/channel.js index bb67fcf4f..fbaa8ce4c 100644 --- a/lib/channel.js +++ b/lib/channel.js @@ -4,6 +4,8 @@ var _createClass = (function () { function defineProperties(target, props) { for function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var ChannelPermissions = require("./ChannelPermissions.js"); + var Channel = (function () { function Channel(data, server) { _classCallCheck(this, Channel); @@ -14,10 +16,49 @@ var Channel = (function () { this.topic = data.topic; this.id = data.id; this.messages = []; - //this.isPrivate = isPrivate; //not sure about the implementation of this... + this.roles = []; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = data.permission_overwrites[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var role = _step.value; + + this.roles.push(new ChannelPermissions(role, this)); + } + + //this.isPrivate = isPrivate; //not sure about the implementation of this... + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator["return"]) { + _iterator["return"](); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } } _createClass(Channel, [{ + key: "permissionsOf", + value: function permissionsOf(member) { + + var mem = this.server.getMember("id", member.id); + + if (mem) { + return mem.permissionsIn(this); + } else { + return null; + } + } + }, { key: "equals", value: function equals(object) { return object && object.id === this.id; @@ -39,29 +80,29 @@ var Channel = (function () { }, { key: "getMessage", value: function getMessage(key, value) { - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; try { - for (var _iterator = this.messages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var message = _step.value; + for (var _iterator2 = this.messages[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var message = _step2.value; if (message[key] === value) { return message; } } } catch (err) { - _didIteratorError = true; - _iteratorError = err; + _didIteratorError2 = true; + _iteratorError2 = err; } finally { try { - if (!_iteratorNormalCompletion && _iterator["return"]) { - _iterator["return"](); + if (!_iteratorNormalCompletion2 && _iterator2["return"]) { + _iterator2["return"](); } } finally { - if (_didIteratorError) { - throw _iteratorError; + if (_didIteratorError2) { + throw _iteratorError2; } } } @@ -73,6 +114,16 @@ var Channel = (function () { value: function toString() { return "<#" + this.id + ">"; } + }, { + key: "permissionOverwrites", + get: function get() { + return this.roles; + } + }, { + key: "permissions", + get: function get() { + return this.roles; + } }, { key: "client", get: function get() { diff --git a/lib/message.js b/lib/message.js index 3dd4ddcae..2e2ddd69d 100644 --- a/lib/message.js +++ b/lib/message.js @@ -20,7 +20,7 @@ var Message = (function () { this.editedTimestamp = data.edited_timestamp; this.content = data.content.trim(); this.channel = channel; - this.author = author; + this.author = this.channel.server.getMember("id", author.id); this.attachments = data.attachments; } diff --git a/lib/server.js b/lib/server.js index c8758d5da..871e30928 100644 --- a/lib/server.js +++ b/lib/server.js @@ -4,6 +4,9 @@ var _createClass = (function () { function defineProperties(target, props) { for function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var ServerPermissions = require("./ServerPermissions.js"); +var Member = require("./Member.js"); + var Server = (function () { function Server(data, client) { _classCallCheck(this, Server); @@ -19,25 +22,17 @@ var Server = (function () { this.afkTimeout = data.afk_timeout; this.afkChannelId = data.afk_channel_id; - if (!data.members) { - data.members = [client.user]; - return; - } + this.roles = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { - for (var _iterator = data.members[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var member = _step.value; + for (var _iterator = data.roles[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var permissionGroup = _step.value; - // first we cache the user in our Discord Client, - // then we add it to our list. This way when we - // get a user from this server's member list, - // it will be identical (unless an async change occurred) - // to the client's cache. - if (member.user) this.members.push(client.addUser(member.user)); + this.roles.push(new ServerPermissions(permissionGroup)); } } catch (err) { _didIteratorError = true; @@ -53,55 +48,59 @@ var Server = (function () { } } } + + if (!data.members) { + data.members = [client.user]; + return; + } + + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = data.members[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var member = _step2.value; + + // first we cache the user in our Discord Client, + // then we add it to our list. This way when we + // get a user from this server's member list, + // it will be identical (unless an async change occurred) + // to the client's cache. + if (member.user) this.addMember(client.addUser(member.user), member.roles); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2["return"]) { + _iterator2["return"](); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } } _createClass(Server, [{ - key: "getChannel", + key: "getRole", // get/set - value: function getChannel(key, value) { - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - try { - for (var _iterator2 = this.channels[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var channel = _step2.value; - - if (channel[key] === value) { - return channel; - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2["return"]) { - _iterator2["return"](); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - return null; - } - }, { - key: "getMember", - value: function getMember(key, value) { + value: function getRole(id) { var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { - for (var _iterator3 = this.members[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { - var member = _step3.value; + for (var _iterator3 = this.roles[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var role = _step3.value; - if (member[key] === value) { - return member; + if (role.id === id) { + return role; } } } catch (err) { @@ -121,6 +120,157 @@ var Server = (function () { return null; } + }, { + key: "updateRole", + value: function updateRole(data) { + + var oldRole = this.getRole(data.id); + + if (oldRole) { + + var index = this.roles.indexOf(oldRole); + this.roles[index] = new ServerPermissions(data); + + return this.roles[index]; + } else { + return false; + } + } + }, { + key: "removeRole", + value: function removeRole(id) { + for (var roleId in this.roles) { + if (this.roles[roleId].id === id) { + this.roles.splice(roleId, 1); + } + } + + var _iteratorNormalCompletion4 = true; + var _didIteratorError4 = false; + var _iteratorError4 = undefined; + + try { + for (var _iterator4 = this.members[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { + var member = _step4.value; + + for (var roleId in member.rawRoles) { + if (member.rawRoles[roleId] === id) { + member.rawRoles.splice(roleId, 1); + } + } + } + } catch (err) { + _didIteratorError4 = true; + _iteratorError4 = err; + } finally { + try { + if (!_iteratorNormalCompletion4 && _iterator4["return"]) { + _iterator4["return"](); + } + } finally { + if (_didIteratorError4) { + throw _iteratorError4; + } + } + } + } + }, { + key: "getChannel", + value: function getChannel(key, value) { + var _iteratorNormalCompletion5 = true; + var _didIteratorError5 = false; + var _iteratorError5 = undefined; + + try { + for (var _iterator5 = this.channels[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { + var channel = _step5.value; + + if (channel[key] === value) { + return channel; + } + } + } catch (err) { + _didIteratorError5 = true; + _iteratorError5 = err; + } finally { + try { + if (!_iteratorNormalCompletion5 && _iterator5["return"]) { + _iterator5["return"](); + } + } finally { + if (_didIteratorError5) { + throw _iteratorError5; + } + } + } + + return null; + } + }, { + key: "getMember", + value: function getMember(key, value) { + var _iteratorNormalCompletion6 = true; + var _didIteratorError6 = false; + var _iteratorError6 = undefined; + + try { + for (var _iterator6 = this.members[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { + var member = _step6.value; + + if (member[key] === value) { + return member; + } + } + } catch (err) { + _didIteratorError6 = true; + _iteratorError6 = err; + } finally { + try { + if (!_iteratorNormalCompletion6 && _iterator6["return"]) { + _iterator6["return"](); + } + } finally { + if (_didIteratorError6) { + throw _iteratorError6; + } + } + } + + return null; + } + }, { + key: "removeMember", + value: function removeMember(key, value) { + var _iteratorNormalCompletion7 = true; + var _didIteratorError7 = false; + var _iteratorError7 = undefined; + + try { + for (var _iterator7 = this.members[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { + var member = _step7.value; + + if (member[key] === value) { + this.members.splice(key, 1); + return member; + } + } + } catch (err) { + _didIteratorError7 = true; + _iteratorError7 = err; + } finally { + try { + if (!_iteratorNormalCompletion7 && _iterator7["return"]) { + _iterator7["return"](); + } + } finally { + if (_didIteratorError7) { + throw _iteratorError7; + } + } + } + + return false; + } }, { key: "addChannel", value: function addChannel(chann) { @@ -131,11 +281,12 @@ var Server = (function () { } }, { key: "addMember", - value: function addMember(member) { - if (!this.getMember("id", member.id)) { - this.members.push(member); + value: function addMember(user, roles) { + if (!this.getMember("id", user.id)) { + var mem = new Member(user, this, roles); + this.members.push(mem); } - return member; + return mem; } }, { key: "toString", @@ -147,6 +298,16 @@ var Server = (function () { value: function equals(object) { return object.id === this.id; } + }, { + key: "permissionGroups", + get: function get() { + return this.roles; + } + }, { + key: "permissions", + get: function get() { + return this.roles; + } }, { key: "iconURL", get: function get() { diff --git a/lib/user.js b/lib/user.js index 5e38e132e..9a3d64c88 100644 --- a/lib/user.js +++ b/lib/user.js @@ -12,7 +12,7 @@ var User = (function () { this.discriminator = data.discriminator; this.id = data.id; this.avatar = data.avatar; - this.status = "offline"; + this.status = data.status || "offline"; } // access using user.avatarURL; diff --git a/src/ChannelPermissions.js b/src/ChannelPermissions.js new file mode 100644 index 000000000..9d6dce2e4 --- /dev/null +++ b/src/ChannelPermissions.js @@ -0,0 +1,87 @@ +class ChannelPermissions{ + constructor(data, channel){ + + var self = this; + + function getBit(x) { + return ((self.packed >>> x) & 1) === 1; + } + + this.type = data.type; //either member or role + this.id = data.id; + + if(this.type === "member"){ + this.packed = channel.server.getMember("id", data.id).evalPerms.packed; + }else{ + this.packed = channel.server.getRole(data.id).packed; + } + + this.packed = this.packed & ~data.deny; + this.packed = this.packed | data.allow; + + this.deny = data.deny; + this.allow = data.allow; + + } + + get createInstantInvite(){return this.getBit(0);} + set createInstantInvite(val){this.setBit(0, val);} + + get manageRoles(){return this.getBit(3);} + set manageRoles(val){this.setBit(3, val);} + + get manageChannels(){return this.getBit(4);} + set manageChannels(val){this.setBit(4, val);} + + get readMessages(){return this.getBit(10);} + set readMessages(val){this.setBit(10, val);} + + get sendMessages(){return this.getBit(11);} + set sendMessages(val){this.setBit(11, val);} + + get sendTTSMessages(){return this.getBit(12);} + set sendTTSMessages(val){this.setBit(12, val);} + + get manageMessages(){return this.getBit(13);} + set manageMessages(val){this.setBit(13, val);} + + get embedLinks(){return this.getBit(14);} + set embedLinks(val){this.setBit(14, val);} + + get attachFiles(){return this.getBit(15);} + set attachFiles(val){this.setBit(15, val);} + + get readMessageHistory(){return this.getBit(16);} + set readMessageHistory(val){this.setBit(16, val);} + + get mentionEveryone(){return this.getBit(17);} + set mentionEveryone(val){this.setBit(17, val);} + + get voiceConnect(){return this.getBit(20);} + set voiceConnect(val){this.setBit(20, val);} + + get voiceSpeak(){return this.getBit(21);} + set voiceSpeak(val){this.setBit(21, val);} + + get voiceMuteMembers(){return this.getBit(22);} + set voiceMuteMembers(val){this.setBit(22, val);} + + get voiceDeafenMembers(){return this.getBit(23);} + set voiceDeafenMembers(val){this.setBit(23, val);} + + get voiceMoveMembers(){return this.getBit(24);} + set voiceMoveMembers(val){this.setBit(24, val);} + + get voiceUseVoiceActivation(){return this.getBit(25);} + set voiceUseVoiceActivation(val){this.setBit(25, val);} + + getBit(x) { + return ((this.packed >>> x) & 1) === 1; + } + + setBit() { + + } +} + +module.exports = ChannelPermissions; \ No newline at end of file diff --git a/src/Client.js b/src/Client.js index 6dd6c0fd9..bede31c3e 100644 --- a/src/Client.js +++ b/src/Client.js @@ -56,7 +56,7 @@ class Client { this.checkingQueue = {}; this.userTypingListener = {}; this.queue = {}; - + this.__idleTime = null; this.__gameId = null; } @@ -399,15 +399,15 @@ class Client { function remove() { request - .del(`${Endpoints.CHANNELS}/${message.channel.id}/messages/${message.id}`) - .set("authorization", self.token) - .end(function (err, res) { - if(err){ - bad(); - }else{ - good(); - } - }); + .del(`${Endpoints.CHANNELS}/${message.channel.id}/messages/${message.id}`) + .set("authorization", self.token) + .end(function (err, res) { + if (err) { + bad(); + } else { + good(); + } + }); } function good() { @@ -420,7 +420,7 @@ class Client { reject(err); } }); - + } updateMessage(message, content, callback = function (err, msg) { }) { @@ -757,7 +757,7 @@ class Client { self.trigger("error", err, e); return; } - + self.trigger("raw", dat); //valid message @@ -938,12 +938,8 @@ class Client { if (server) { var user = self.addUser(data.user); //if for whatever reason it doesn't exist.. - - if (!~server.members.indexOf(user)) { - server.members.push(user); - } - self.trigger("serverNewMember", user, server); + self.trigger("serverNewMember", server.addMember(user, data.roles), server); } break; @@ -956,10 +952,8 @@ class Client { var user = self.addUser(data.user); //if for whatever reason it doesn't exist.. - if (~server.members.indexOf(user)) { - server.members.splice(server.members.indexOf(user), 1); - } - + server.removeMember("id", user.id); + self.trigger("serverRemoveMember", user, server); } @@ -1007,45 +1001,66 @@ class Client { } break; - + case "CHANNEL_UPDATE": - + var channelInCache = self.getChannel("id", data.id), serverInCache = self.getServer("id", data.guild_id); - - if(channelInCache && serverInCache){ - + + if (channelInCache && serverInCache) { + var newChann = new Channel(data, serverInCache); newChann.messages = channelInCache.messages; - + self.trigger("channelUpdate", channelInCache, newChann); - - self.channelCache[ self.channelCache.indexOf(channelInCache) ] = newChann; + + self.channelCache[self.channelCache.indexOf(channelInCache)] = newChann; } - + break; - + case "TYPING_START": - + var userInCache = self.getUser("id", data.user_id); var channelInCache = self.getChannel("id", data.channel_id); - - if(!self.userTypingListener[data.user_id] || self.userTypingListener[data.user_id] === -1){ + + if (!self.userTypingListener[data.user_id] || self.userTypingListener[data.user_id] === -1) { self.trigger("startTyping", userInCache, channelInCache); } - + self.userTypingListener[data.user_id] = Date.now(); - - setTimeout(function(){ - if(self.userTypingListener[data.user_id] === -1){ + + setTimeout(function () { + if (self.userTypingListener[data.user_id] === -1) { return; } - if( Date.now() - self.userTypingListener[data.user_id] > 6000 ){ + if (Date.now() - self.userTypingListener[data.user_id] > 6000) { // stopped typing self.trigger("stopTyping", userInCache, channelInCache); self.userTypingListener[data.user_id] = -1; } }, 6000); + + break; + + case "GUILD_ROLE_DELETE": + + var server = self.getServer("id", data.guild_id); + var role = server.getRole(data.role_id); + + self.trigger("serverRoleDelete", server, role); + + server.removeRole(role.id); + + break; + + case "GUILD_ROLE_UPDATE": + + var server = self.getServer("id", data.guild_id); + var role = server.getRole(data.role.id); + var newRole = server.updateRole(data.role); + + self.trigger("serverRoleUpdate", server, role, newRole); break; @@ -1082,45 +1097,45 @@ class Client { } return this.getPMChannel("id", data.id); } - - setTopic(channel, topic, callback = function(err){}){ - + + setTopic(channel, topic, callback = function (err) { }) { + var self = this; - - return new Promise(function(resolve, reject){ - + + return new Promise(function (resolve, reject) { + self.resolveDestination(channel).then(next).catch(error); - - function error(e){ + + function error(e) { callback(e); reject(e); } - - function next(destination){ - + + function next(destination) { + var asChan = self.getChannel("id", destination); - + request .patch(`${Endpoints.CHANNELS}/${destination}`) .set("authorization", self.token) .send({ - name : asChan.name, - position : 0, - topic : topic + name: asChan.name, + position: 0, + topic: topic }) - .end(function(err, res){ - if(err){ + .end(function (err, res) { + if (err) { error(err); - }else{ + } else { asChan.topic = res.body.topic; resolve(); callback(); } - }); + }); } - + }); - + } //def addServer @@ -1129,7 +1144,7 @@ class Client { var self = this; var server = this.getServer("id", data.id); - if(data.unavailable){ + if (data.unavailable) { self.trigger("unavailable", data); self.debug("Server ID " + data.id + " has been marked unavailable by Discord. It was not cached."); return; @@ -1144,8 +1159,8 @@ class Client { } } } - - for(var presence of data.presences){ + + for (var presence of data.presences) { self.getUser("id", presence.user.id).status = presence.status; } @@ -1370,132 +1385,132 @@ class Client { }); }); } - - setStatusIdle(){ + + setStatusIdle() { this.setStatus("idle"); } - - setStatusOnline(){ + + setStatusOnline() { this.setStatus("online"); } - - setStatusActive(){ + + setStatusActive() { this.setStatusOnline(); } - - setStatusHere(){ + + setStatusHere() { this.setStatusOnline(); } - - setStatusAway(){ + + setStatusAway() { this.setStatusIdle(); } - - startTyping(chann, stopTypeTime){ + + startTyping(chann, stopTypeTime) { var self = this; - + this.resolveDestination(chann).then(next); - - function next(channel){ - if(self.typingIntervals[channel]){ + + function next(channel) { + if (self.typingIntervals[channel]) { return; } - - var fn = function(){ + + var fn = function () { request - .post(`${Endpoints.CHANNELS}/${channel}/typing`) - .set("authorization", self.token) - .end(); + .post(`${Endpoints.CHANNELS}/${channel}/typing`) + .set("authorization", self.token) + .end(); }; - + fn(); - + var interval = setInterval(fn, 3000); - + self.typingIntervals[channel] = interval; - - if(stopTypeTime){ - setTimeout(function(){ + + if (stopTypeTime) { + setTimeout(function () { self.stopTyping(channel); }, stopTypeTime); } } } - - stopTyping(chann){ + + stopTyping(chann) { var self = this; - + this.resolveDestination(chann).then(next); - - function next(channel){ - if(!self.typingIntervals[channel]){ + + function next(channel) { + if (!self.typingIntervals[channel]) { return; } - + clearInterval(self.typingIntervals[channel]); - + delete self.typingIntervals[channel]; - + } } - - setStatus(stat){ - + + setStatus(stat) { + var idleTime = (stat === "online" ? null : Date.now()); - + this.__idleTime = idleTime; - + this.websocket.send(JSON.stringify({ - op : 3, - d : { - idle_since : this.__idleTime, - game_id : this.__gameId + op: 3, + d: { + idle_since: this.__idleTime, + game_id: this.__gameId } })); } - - setPlayingGame(id){ - - if( id instanceof String || typeof id === `string` ){ + + setPlayingGame(id) { + + if (id instanceof String || typeof id === `string`) { // working on names var gid = id.trim().toUpperCase(); - + id = null; - - for( var game of gameMap ){ - - if(game.name.trim().toUpperCase() === gid){ - + + for (var game of gameMap) { + + if (game.name.trim().toUpperCase() === gid) { + id = game.id; break; - + } - + } - + } - + this.__gameId = id; - + this.websocket.send(JSON.stringify({ - op : 3, - d : { - idle_since : this.__idleTime, - game_id : this.__gameId + op: 3, + d: { + idle_since: this.__idleTime, + game_id: this.__gameId } })); - + } - - playGame(id){ + + playGame(id) { this.setPlayingGame(id); } - - playingGame(id){ - + + playingGame(id) { + this.setPlayingGame(id); - + } } diff --git a/src/EvaluatedPermissions.js b/src/EvaluatedPermissions.js new file mode 100644 index 000000000..5fef65fe9 --- /dev/null +++ b/src/EvaluatedPermissions.js @@ -0,0 +1,76 @@ +class EvaluatedPermissions { + constructor(data) { + + var self = this; + + function getBit(x) { + if (((self.packed >>> 3) & 1) === 1) { + return true; + } + return ((self.packed >>> x) & 1) === 1; + } + + this.packed = data; + } + + get createInstantInvite() { return this.getBit(0); } + set createInstantInvite(val) { this.setBit(0, val); } + + get manageRoles() { return this.getBit(3); } + set manageRoles(val) { this.setBit(3, val); } + + get manageChannels() { return this.getBit(4); } + set manageChannels(val) { this.setBit(4, val); } + + get readMessages() { return this.getBit(10); } + set readMessages(val) { this.setBit(10, val); } + + get sendMessages() { return this.getBit(11); } + set sendMessages(val) { this.setBit(11, val); } + + get sendTTSMessages() { return this.getBit(12); } + set sendTTSMessages(val) { this.setBit(12, val); } + + get manageMessages() { return this.getBit(13); } + set manageMessages(val) { this.setBit(13, val); } + + get embedLinks() { return this.getBit(14); } + set embedLinks(val) { this.setBit(14, val); } + + get attachFiles() { return this.getBit(15); } + set attachFiles(val) { this.setBit(15, val); } + + get readMessageHistory() { return this.getBit(16); } + set readMessageHistory(val) { this.setBit(16, val); } + + get mentionEveryone() { return this.getBit(17); } + set mentionEveryone(val) { this.setBit(17, val); } + + get voiceConnect() { return this.getBit(20); } + set voiceConnect(val) { this.setBit(20, val); } + + get voiceSpeak() { return this.getBit(21); } + set voiceSpeak(val) { this.setBit(21, val); } + + get voiceMuteMembers() { return this.getBit(22); } + set voiceMuteMembers(val) { this.setBit(22, val); } + + get voiceDeafenMembers() { return this.getBit(23); } + set voiceDeafenMembers(val) { this.setBit(23, val); } + + get voiceMoveMembers() { return this.getBit(24); } + set voiceMoveMembers(val) { this.setBit(24, val); } + + get voiceUseVoiceActivation() { return this.getBit(25); } + set voiceUseVoiceActivation(val) { this.setBit(25, val); } + + getBit(x) { + return ((this.packed >>> x) & 1) === 1; + } + + setBit() { + + } +} + +module.exports = EvaluatedPermissions; \ No newline at end of file diff --git a/src/Member.js b/src/Member.js index 3fa49ebd6..9ac6c644b 100644 --- a/src/Member.js +++ b/src/Member.js @@ -1,12 +1,81 @@ var User = require("./user.js"); +var ServerPermissions = require("./ServerPermissions.js"); +var EvaluatedPermissions = require("./EvaluatedPermissions.js"); class Member extends User{ - constructor(data){ - super(data); + constructor(user, server, roles){ + super(user); // should work, we are basically creating a Member that has the same properties as user and a few more + this.server = server; + this.rawRoles = roles; + } + + get roles(){ + var ufRoles = [ this.server.getRole(this.server.id) ]; + + for(var rawRole of this.rawRoles){ + ufRoles.push( this.server.getRole(rawRole) ); + } + return ufRoles; } -} \ No newline at end of file + get evalPerms(){ + var basePerms = this.roles, //cache roles as it can be slightly expensive + basePerm = basePerms[0].packed; + + for(var perm of basePerms){ + basePerm = basePerm | perm.packed; + } + + return new ServerPermissions({ + permissions : basePerm + }); + } + + permissionsIn(channel){ + + if(channel.server.ownerID === this.id){ + return new EvaluatedPermissions(4294967295); //all perms + } + + var affectingOverwrites = []; + var affectingMemberOverwrites = []; + + for(var overwrite of channel.roles){ + if(overwrite.id === this.id && overwrite.type === "member"){ + affectingMemberOverwrites.push(overwrite); + }else if( this.rawRoles.indexOf(overwrite.id) !== -1 ){ + affectingOverwrites.push(overwrite); + } + } + + for(var perm of affectingOverwrites){ + console.log("hey", perm.attachFiles); + } + + if(affectingOverwrites.length === 0 && affectingMemberOverwrites.length === 0){ + return new EvaluatedPermissions(this.evalPerms.packed); + } + + var finalPacked = (affectingOverwrites.length !== 0 ? affectingOverwrites[0].packed : affectingMemberOverwrites[0].packed); + + for(var overwrite of affectingOverwrites){ + finalPacked = finalPacked & ~overwrite.deny; + finalPacked = finalPacked | overwrite.allow; + } + + for(var overwrite of affectingMemberOverwrites){ + finalPacked = finalPacked & ~overwrite.deny; + finalPacked = finalPacked | overwrite.allow; + } + + return new EvaluatedPermissions(finalPacked); + + } + +} + +module.exports = Member; \ No newline at end of file diff --git a/src/Permissions.js b/src/Permissions.js deleted file mode 100644 index e0dc4d424..000000000 --- a/src/Permissions.js +++ /dev/null @@ -1,38 +0,0 @@ -class Permission { - - constructor(packedPermissions) { - - function getBit(x) { - return ((this.packed >>> x) & 1) === 1; - } - - this.packed = packedPermissions; - - this.createInstantInvite = getBit(0); - this.banMembers = getBit(1); - this.kickMembers = getBit(2); - this.manageRoles = getBit(3); - this.manageChannels = getBit(4); - this.manageServer = getBit(5); - this.readMessages = getBit(10); - this.sendMessages = getBit(11); - this.sendTTSMessages = getBit(12); - this.manageMessages = getBit(13); - this.embedLinks = getBit(14); - this.attachFiles = getBit(15); - this.readMessageHistory = getBit(16); - this.mentionEveryone = getBit(17); - - this.voiceConnect = getBit(20); - this.voiceSpeak = getBit(21); - this.voiceMuteMembers = getBit(22); - this.voiceDeafenMembers = getBit(23); - this.voiceMoveMembers = getBit(24); - this.voiceUseVoiceActivation = getBit(26); - - } - - getBit(x) { - return ((this.packed >>> x) & 1) === 1; - } -} \ No newline at end of file diff --git a/src/ServerPermissions.js b/src/ServerPermissions.js new file mode 100644 index 000000000..b3fd848ae --- /dev/null +++ b/src/ServerPermissions.js @@ -0,0 +1,90 @@ +class ServerPermissions { + + constructor(data) { + + var self = this; + + function getBit(x) { + return ((self.packed >>> x) & 1) === 1; + } + + this.packed = data.permissions; + this.name = data.name; + this.id = data.id; + + } + + get createInstantInvite(){return this.getBit(0);} + set createInstantInvite(val){this.setBit(0, val);} + + get banMembers(){return this.getBit(1);} + set banMembers(val){this.setBit(1, val);} + + get kickMembers(){return this.getBit(2);} + set kickMembers(val){this.setBit(2, val);} + + get manageRoles(){return this.getBit(3);} + set manageRoles(val){this.setBit(3, val);} + + get manageChannels(){return this.getBit(4);} + set manageChannels(val){this.setBit(4, val);} + + get manageServer(){return this.getBit(5);} + set manageServer(val){this.setBit(5, val);} + + get readMessages(){return this.getBit(10);} + set readMessages(val){this.setBit(10, val);} + + get sendMessages(){return this.getBit(11);} + set sendMessages(val){this.setBit(11, val);} + + get sendTTSMessages(){return this.getBit(12);} + set sendTTSMessages(val){this.setBit(12, val);} + + get manageMessages(){return this.getBit(13);} + set manageMessages(val){this.setBit(13, val);} + + get embedLinks(){return this.getBit(14);} + set embedLinks(val){this.setBit(14, val);} + + get attachFiles(){return this.getBit(15);} + set attachFiles(val){this.setBit(15, val);} + + get readMessageHistory(){return this.getBit(16);} + set readMessageHistory(val){this.setBit(16, val);} + + get mentionEveryone(){return this.getBit(17);} + set mentionEveryone(val){this.setBit(17, val);} + + get voiceConnect(){return this.getBit(20);} + set voiceConnect(val){this.setBit(20, val);} + + get voiceSpeak(){return this.getBit(21);} + set voiceSpeak(val){this.setBit(21, val);} + + get voiceMuteMembers(){return this.getBit(22);} + set voiceMuteMembers(val){this.setBit(22, val);} + + get voiceDeafenMembers(){return this.getBit(23);} + set voiceDeafenMembers(val){this.setBit(23, val);} + + get voiceMoveMembers(){return this.getBit(24);} + set voiceMoveMembers(val){this.setBit(24, val);} + + get voiceUseVoiceActivation(){return this.getBit(25);} + set voiceUseVoiceActivation(val){this.setBit(25, val);} + + getBit(x) { + return ((this.packed >>> x) & 1) === 1; + } + + setBit(){ + //dummy function for now + } + + toString(){ + return this.name; + } +} + +module.exports = ServerPermissions; \ No newline at end of file diff --git a/src/channel.js b/src/channel.js index a7185e17f..6e3b2ef99 100644 --- a/src/channel.js +++ b/src/channel.js @@ -1,3 +1,5 @@ +var ChannelPermissions = require("./ChannelPermissions.js"); + class Channel { constructor(data, server) { @@ -7,52 +9,80 @@ class Channel { this.topic = data.topic; this.id = data.id; this.messages = []; + this.roles = []; + + for (var role of data.permission_overwrites) { + + this.roles.push( new ChannelPermissions(role, this) ); + + } + //this.isPrivate = isPrivate; //not sure about the implementation of this... } + get permissionOverwrites() { + return this.roles; + } + + get permissions() { + return this.roles; + } + get client() { return this.server.client; } + permissionsOf(member){ + + var mem = this.server.getMember("id", member.id); + + if(mem){ + return mem.permissionsIn(this); + }else{ + return null; + } + + } + equals(object) { return (object && object.id === this.id); } - - addMessage(data){ - - if(this.messages.length > 1000){ - this.messages.splice(0,1); - } - - if(!this.getMessage("id", data.id)){ - this.messages.push(data); - } - - return this.getMessage("id", data.id); - } - - getMessage(key, value){ - for(var message of this.messages){ - if(message[key] === value){ - return message; - } - } - return null; - } - toString(){ + addMessage(data) { + + if (this.messages.length > 1000) { + this.messages.splice(0, 1); + } + + if (!this.getMessage("id", data.id)) { + this.messages.push(data); + } + + return this.getMessage("id", data.id); + } + + getMessage(key, value) { + for (var message of this.messages) { + if (message[key] === value) { + return message; + } + } + return null; + } + + toString() { return "<#" + this.id + ">"; } - - get isPrivate(){ + + get isPrivate() { return false; } - - get users(){ + + get users() { return this.server.members; } - - get members(){ + + get members() { return this.server.members; } } diff --git a/src/message.js b/src/message.js index 3462ce88c..1cbc8be7e 100644 --- a/src/message.js +++ b/src/message.js @@ -12,7 +12,7 @@ class Message{ this.editedTimestamp = data.edited_timestamp; this.content = data.content.trim(); this.channel = channel; - this.author = author; + this.author = this.channel.server.getMember("id", author.id); this.attachments = data.attachments; } diff --git a/src/server.js b/src/server.js index d0d56578c..458afa5e2 100644 --- a/src/server.js +++ b/src/server.js @@ -1,3 +1,6 @@ +var ServerPermissions = require("./ServerPermissions.js"); +var Member = require("./Member.js"); + class Server { constructor(data, client) { this.client = client; @@ -10,6 +13,12 @@ class Server { this.icon = data.icon; this.afkTimeout = data.afk_timeout; this.afkChannelId = data.afk_channel_id; + + this.roles = []; + + for(var permissionGroup of data.roles){ + this.roles.push( new ServerPermissions(permissionGroup) ); + } if(!data.members){ data.members = [ client.user ]; @@ -24,10 +33,18 @@ class Server { // it will be identical (unless an async change occurred) // to the client's cache. if(member.user) - this.members.push(client.addUser(member.user)); + this.addMember(client.addUser(member.user), member.roles); } } + + get permissionGroups(){ + return this.roles; + } + + get permissions(){ + return this.roles; + } get iconURL() { if (!this.icon) @@ -55,6 +72,51 @@ class Server { } // get/set + + getRole(id){ + for (var role of this.roles) { + if (role.id === id) { + return role; + } + } + + return null; + } + + updateRole(data){ + + var oldRole = this.getRole(data.id); + + if(oldRole){ + + var index = this.roles.indexOf(oldRole); + this.roles[index] = new ServerPermissions(data); + + + return this.roles[index]; + + }else{ + return false; + } + + } + + removeRole(id){ + for (var roleId in this.roles) { + if (this.roles[roleId].id === id) { + this.roles.splice(roleId, 1); + } + } + + for(var member of this.members){ + for(var roleId in member.rawRoles){ + if(member.rawRoles[roleId] === id){ + member.rawRoles.splice(roleId, 1); + } + } + } + } + getChannel(key, value) { for (var channel of this.channels) { if (channel[key] === value) { @@ -75,6 +137,17 @@ class Server { return null; } + removeMember(key, value){ + for (var member of this.members) { + if (member[key] === value) { + this.members.splice(key, 1); + return member; + } + } + + return false; + } + addChannel(chann) { if (!this.getChannel("id", chann.id)) { this.channels.push(chann); @@ -82,11 +155,12 @@ class Server { return chann; } - addMember(member){ - if (!this.getMember("id", member.id)){ - this.members.push(member); + addMember(user, roles){ + if (!this.getMember("id", user.id)){ + var mem = new Member(user, this, roles); + this.members.push(mem); } - return member; + return mem; } toString(){ diff --git a/src/user.js b/src/user.js index 73eef604f..9686fed27 100644 --- a/src/user.js +++ b/src/user.js @@ -4,7 +4,7 @@ class User{ this.discriminator = data.discriminator; this.id = data.id; this.avatar = data.avatar; - this.status = "offline"; + this.status = data.status || "offline"; } // access using user.avatarURL; diff --git a/test/bot.1.js b/test/bot.1.js index d1eb296a7..9f324f719 100644 --- a/test/bot.1.js +++ b/test/bot.1.js @@ -9,21 +9,26 @@ counter = 1; mybot.on("message", function (message) { console.log("Everyone mentioned? " + message.everyoneMentioned); - if (mybot.user.equals(message.sender)) { - return; - } - - if (message.content !== "$$$") { + if (message.content.substr(0,3) !== "$$$") { return; } // we can go ahead :) - var onlineUsers = 0; + var user; + if(message.mentions.length > 0){ + user = message.mentions[0]; + }else{ + user = message.sender; + } - counter++; - - mybot.playingGame( "Minecraft" ); + console.log("the ID is ", user.id); + + for(key in message.channel.permissionsOf(user)){ + console.log(key); + } + + mybot.reply(message, user + "'s evaluated permissions in this channel are " + message.channel.permissionsOf(user).sendTTSMessages); }); @@ -48,8 +53,6 @@ mybot.on("unknown", function(info){ mybot.on("channelUpdate", function(oldChan, newChan){ - console.log(oldChan.topic + " vs " + newChan.topic); - }); mybot.on("startTyping", function(user, channel){