You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

384 lines
8.9 KiB
Lua

--[=[
@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