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
384 lines
8.9 KiB
Lua
3 years ago
|
--[=[
|
||
|
@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
|