--[=[ @c Role x Snowflake @d Represents a Discord guild role, which is used to assign priority, permissions, and a color to guild members. ]=] local json = require('json') local Snowflake = require('containers/abstract/Snowflake') local Color = require('utils/Color') local Permissions = require('utils/Permissions') local Resolver = require('client/Resolver') local FilteredIterable = require('iterables/FilteredIterable') local format = string.format local insert, sort = table.insert, table.sort local min, max, floor = math.min, math.max, math.floor local huge = math.huge local Role, get = require('class')('Role', Snowflake) function Role:__init(data, parent) Snowflake.__init(self, data, parent) self.client._role_map[self._id] = parent end function Role:_modify(payload) local data, err = self.client._api:modifyGuildRole(self._parent._id, self._id, payload) if data then self:_load(data) return true else return false, err end end --[=[ @m delete @t http @r boolean @d Permanently deletes the role. This cannot be undone! ]=] function Role:delete() local data, err = self.client._api:deleteGuildRole(self._parent._id, self._id) if data then local cache = self._parent._roles if cache then cache:_delete(self._id) end return true else return false, err end end local function sorter(a, b) if a.position == b.position then return tonumber(a.id) < tonumber(b.id) else return a.position < b.position end end local function getSortedRoles(self) local guild = self._parent local id = self._parent._id local ret = {} for role in guild.roles:iter() do if role._id ~= id then insert(ret, {id = role._id, position = role._position}) end end sort(ret, sorter) return ret end local function setSortedRoles(self, roles) local id = self._parent._id insert(roles, {id = id, position = 0}) local data, err = self.client._api:modifyGuildRolePositions(id, roles) if data then return true else return false, err end end --[=[ @m moveDown @t http @p n number @r boolean @d Moves a role down its list. The parameter `n` indicates how many spaces the role should be moved, clamped to the lowest position, with a default of 1 if it is omitted. This will also normalize the positions of all roles. Note that the default everyone role cannot be moved. ]=] function Role:moveDown(n) -- TODO: fix attempt to move roles that cannot be moved n = tonumber(n) or 1 if n < 0 then return self:moveDown(-n) end local roles = getSortedRoles(self) local new = huge for i = #roles, 1, -1 do local v = roles[i] if v.id == self._id then new = max(1, i - floor(n)) v.position = new elseif i >= new then v.position = i + 1 else v.position = i end end return setSortedRoles(self, roles) end --[=[ @m moveUp @t http @p n number @r boolean @d Moves a role up its list. The parameter `n` indicates how many spaces the role should be moved, clamped to the highest position, with a default of 1 if it is omitted. This will also normalize the positions of all roles. Note that the default everyone role cannot be moved. ]=] function Role:moveUp(n) -- TODO: fix attempt to move roles that cannot be moved n = tonumber(n) or 1 if n < 0 then return self:moveUp(-n) end local roles = getSortedRoles(self) local new = -huge for i = 1, #roles do local v = roles[i] if v.id == self._id then new = min(i + floor(n), #roles) v.position = new elseif i <= new then v.position = i - 1 else v.position = i end end return setSortedRoles(self, roles) end --[=[ @m setName @t http @p name string @r boolean @d Sets the role's name. The name must be between 1 and 100 characters in length. ]=] function Role:setName(name) return self:_modify({name = name or json.null}) end --[=[ @m setColor @t http @p color Color-Resolvable @r boolean @d Sets the role's display color. ]=] function Role:setColor(color) color = color and Resolver.color(color) return self:_modify({color = color or json.null}) end --[=[ @m setPermissions @t http @p permissions Permissions-Resolvable @r boolean @d Sets the permissions that this role explicitly allows. ]=] function Role:setPermissions(permissions) permissions = permissions and Resolver.permissions(permissions) return self:_modify({permissions = permissions or json.null}) end --[=[ @m hoist @t http @r boolean @d Causes members with this role to display above unhoisted roles in the member list. ]=] function Role:hoist() return self:_modify({hoist = true}) end --[=[ @m unhoist @t http @r boolean @d Causes member with this role to display amongst other unhoisted members. ]=] function Role:unhoist() return self:_modify({hoist = false}) end --[=[ @m enableMentioning @t http @r boolean @d Allows anyone to mention this role in text messages. ]=] function Role:enableMentioning() return self:_modify({mentionable = true}) end --[=[ @m disableMentioning @t http @r boolean @d Disallows anyone to mention this role in text messages. ]=] function Role:disableMentioning() return self:_modify({mentionable = false}) end --[=[ @m enablePermissions @t http @p ... Permission-Resolvables @r boolean @d Enables individual permissions for this role. This does not necessarily fully allow the permissions. ]=] function Role:enablePermissions(...) local permissions = self:getPermissions() permissions:enable(...) return self:setPermissions(permissions) end --[=[ @m disablePermissions @t http @p ... Permission-Resolvables @r boolean @d Disables individual permissions for this role. This does not necessarily fully disallow the permissions. ]=] function Role:disablePermissions(...) local permissions = self:getPermissions() permissions:disable(...) return self:setPermissions(permissions) end --[=[ @m enableAllPermissions @t http @r boolean @d Enables all permissions for this role. This does not necessarily fully allow the permissions. ]=] function Role:enableAllPermissions() local permissions = self:getPermissions() permissions:enableAll() return self:setPermissions(permissions) end --[=[ @m disableAllPermissions @t http @r boolean @d Disables all permissions for this role. This does not necessarily fully disallow the permissions. ]=] function Role:disableAllPermissions() local permissions = self:getPermissions() permissions:disableAll() return self:setPermissions(permissions) end --[=[ @m getColor @t mem @r Color @d Returns a color object that represents the role's display color. ]=] function Role:getColor() return Color(self._color) end --[=[ @m getPermissions @t mem @r Permissions @d Returns a permissions object that represents the permissions that this role has enabled. ]=] function Role:getPermissions() return Permissions(self._permissions) end --[=[@p hoisted boolean Whether members with this role should be shown separated from other members in the guild member list.]=] function get.hoisted(self) return self._hoist end --[=[@p mentionable boolean Whether this role can be mentioned in a text channel message.]=] function get.mentionable(self) return self._mentionable end --[=[@p managed boolean Whether this role is managed by some integration or bot inclusion.]=] function get.managed(self) return self._managed end --[=[@p name string The name of the role. This should be between 1 and 100 characters in length.]=] function get.name(self) return self._name end --[=[@p position number The position of the role, where 0 is the lowest.]=] function get.position(self) return self._position end --[=[@p color number Represents the display color of the role as a decimal value.]=] function get.color(self) return self._color end --[=[@p permissions number Represents the total permissions of the role as a decimal value.]=] function get.permissions(self) return self._permissions end --[=[@p mentionString string A string that, when included in a message content, may resolve as a role notification in the official Discord client.]=] function get.mentionString(self) return format('<@&%s>', self._id) end --[=[@p guild Guild The guild in which this role exists.]=] function get.guild(self) return self._parent end --[=[@p members FilteredIterable A filtered iterable of guild members that have this role. If you want to check whether a specific member has this role, it would be better to get the member object elsewhere and use `Member:hasRole` rather than check whether the member exists here.]=] function get.members(self) if not self._members then self._members = FilteredIterable(self._parent._members, function(m) return m:hasRole(self) end) end return self._members end --[=[@p emojis FilteredIterable A filtered iterable of guild emojis that have this role. If you want to check whether a specific emoji has this role, it would be better to get the emoji object elsewhere and use `Emoji:hasRole` rather than check whether the emoji exists here.]=] function get.emojis(self) if not self._emojis then self._emojis = FilteredIterable(self._parent._emojis, function(e) return e:hasRole(self) end) end return self._emojis end return Role