2020-06-20 18:08:48 +00:00
|
|
|
import json, discordobject, nimcordutils, user, member, httpcore, asyncdispatch, emoji, options, embed, role, emoji
|
2020-05-31 05:08:44 +00:00
|
|
|
|
|
|
|
type
|
|
|
|
MessageType* = enum
|
|
|
|
default = 0,
|
|
|
|
recipientAdd = 1,
|
|
|
|
recipientRemove = 2,
|
|
|
|
call = 3,
|
|
|
|
channelNameChange = 4,
|
|
|
|
channelIconChange = 5,
|
|
|
|
channelPinnedMessage = 6,
|
|
|
|
guildMemberJoin = 7,
|
|
|
|
userPremiumGuildSubscription = 8,
|
|
|
|
userPremiumGuildSubscriptionTier1 = 9,
|
|
|
|
userPremiumGuildSubscriptionTier2 = 10,
|
|
|
|
userPremiumGuildSubscriptionTier3 = 11,
|
|
|
|
channelFollowAdd = 12,
|
|
|
|
guildDiscoveryDisqualified = 14,
|
|
|
|
guildDiscoveryRequalified = 15
|
|
|
|
|
|
|
|
MessageActivityType* = enum
|
|
|
|
join = 1,
|
|
|
|
spectate = 2,
|
|
|
|
listen = 3,
|
|
|
|
joinRequest = 5
|
|
|
|
|
2020-06-18 21:12:00 +00:00
|
|
|
MessageActivity* = ref object
|
2020-05-31 05:08:44 +00:00
|
|
|
`type`*: MessageActivityType
|
|
|
|
partyID*: string
|
|
|
|
|
2020-06-18 21:12:00 +00:00
|
|
|
MessageApplication* = ref object of DiscordObject
|
2020-06-18 22:48:48 +00:00
|
|
|
coverImage*: string
|
|
|
|
description*: string
|
|
|
|
icon*: string
|
|
|
|
name*: string
|
2020-05-31 05:08:44 +00:00
|
|
|
|
2020-06-18 21:12:00 +00:00
|
|
|
MessageReference* = ref object
|
2020-06-18 22:48:48 +00:00
|
|
|
messageID*: snowflake
|
|
|
|
channelID*: snowflake
|
|
|
|
guildID*: snowflake
|
2020-05-31 05:08:44 +00:00
|
|
|
|
2020-06-18 20:31:51 +00:00
|
|
|
MessageFlags* = enum
|
|
|
|
msgFlagCrossposted = 0,
|
|
|
|
msgFlagIsCrossPost = 1,
|
|
|
|
msgFlagSuppressEmbeds = 2,
|
|
|
|
msgFlagSourceMsgDeleted = 3,
|
|
|
|
msgFlagUrgent = 4
|
|
|
|
|
2020-06-20 18:08:48 +00:00
|
|
|
Reaction* = ref object
|
|
|
|
count*: uint
|
|
|
|
me*: bool ## Whether the current user has reacted using this emoji.
|
|
|
|
emoji*: Emoji
|
|
|
|
|
|
|
|
ChannelMention* = ref object
|
|
|
|
## Represents a channel mention inside of a message.
|
|
|
|
channelID*: snowflake
|
|
|
|
guildID*: snowflake
|
|
|
|
channelType*: int
|
|
|
|
name*: string
|
|
|
|
|
|
|
|
MessageAttachment* = ref object of DiscordObject
|
|
|
|
## Represents a message attachment
|
|
|
|
filename*: string
|
|
|
|
size*: uint
|
|
|
|
url*: string
|
|
|
|
proxyURL*: string
|
|
|
|
height*: int
|
|
|
|
width*: int
|
|
|
|
|
2020-06-18 20:45:31 +00:00
|
|
|
Message* = ref object of DiscordObject
|
2020-05-31 05:08:44 +00:00
|
|
|
channelID*: snowflake
|
|
|
|
guildID*: snowflake
|
|
|
|
author*: User
|
|
|
|
member*: GuildMember
|
|
|
|
content*: string
|
|
|
|
timestamp*: string
|
|
|
|
editedTimestamp*: string
|
|
|
|
tts*: bool
|
|
|
|
mentionEveryone*: bool
|
|
|
|
mentions*: seq[User]
|
2020-06-20 18:08:48 +00:00
|
|
|
mentionRoles*: seq[snowflake]
|
|
|
|
mentionChannels*: seq[ChannelMention]
|
|
|
|
attachments*: seq[MessageAttachment]
|
|
|
|
embeds*: seq[Embed]
|
|
|
|
reactions*: seq[Reaction]
|
2020-05-31 05:08:44 +00:00
|
|
|
pinned*: bool
|
|
|
|
webhookID*: snowflake
|
|
|
|
`type`*: MessageType
|
|
|
|
activity*: MessageActivity
|
|
|
|
application*: MessageApplication
|
|
|
|
messageReference*: MessageReference
|
|
|
|
flags*: int
|
|
|
|
|
2020-05-31 06:15:16 +00:00
|
|
|
proc newMessage*(messageJson: JsonNode): Message =
|
2020-05-31 05:08:44 +00:00
|
|
|
var msg = Message(
|
2020-05-31 06:15:16 +00:00
|
|
|
id: getIDFromJson(messageJson["id"].getStr()),
|
2020-06-18 03:16:08 +00:00
|
|
|
channelID: getIDFromJson(messageJson["channel_id"].getStr()),
|
|
|
|
guildID: getIDFromJson(messageJson{"guild_id"}.getStr()),
|
2020-05-31 06:15:16 +00:00
|
|
|
content: messageJson["content"].getStr(),
|
|
|
|
timestamp: messageJson["timestamp"].getStr(),
|
|
|
|
editedTimestamp: messageJson{"edited_timestamp"}.getStr(),
|
|
|
|
tts: messageJson["tts"].getBool(),
|
|
|
|
mentionEveryone: messageJson["mention_everyone"].getBool(),
|
|
|
|
pinned: messageJson["pinned"].getBool(),
|
2020-06-18 03:16:08 +00:00
|
|
|
webhookID: getIDFromJson(messageJson{"webhook_id"}.getStr()),
|
2020-05-31 06:15:16 +00:00
|
|
|
`type`: MessageType(messageJson["type"].getInt()),
|
|
|
|
flags: messageJson{"flags"}.getInt()
|
2020-05-31 05:08:44 +00:00
|
|
|
)
|
|
|
|
|
2020-05-31 06:15:16 +00:00
|
|
|
if (messageJson.contains("author")):
|
|
|
|
msg.author = newUser(messageJson["author"])
|
|
|
|
if (messageJson.contains("member")):
|
2020-06-19 21:10:39 +00:00
|
|
|
msg.member = newGuildMember(messageJson["member"], msg.guildID)
|
2020-05-31 05:08:44 +00:00
|
|
|
|
2020-05-31 06:15:16 +00:00
|
|
|
if (messageJson.contains("mentions")):
|
2020-06-20 18:08:48 +00:00
|
|
|
for userJson in messageJson["mentions"]:
|
2020-05-31 05:08:44 +00:00
|
|
|
msg.mentions.add(newUser(userJson))
|
2020-06-20 18:08:48 +00:00
|
|
|
|
|
|
|
for role in messageJson["mention_roles"]:
|
|
|
|
msg.mentionRoles.add(getIDFromJson(role.getStr()))
|
|
|
|
|
|
|
|
if (messageJson.contains("mention_channels")):
|
|
|
|
for channel in messageJson["mention_channels"]:
|
|
|
|
msg.mentionChannels.add(ChannelMention(
|
|
|
|
channelID: getIDFromJson(channel["id"].getStr()),
|
|
|
|
guildID: getIDFromJson(channel["guild_id"].getStr()),
|
|
|
|
channelType: channel["type"].getInt(),
|
|
|
|
name: channel["tyoe"].getStr()
|
|
|
|
))
|
|
|
|
|
|
|
|
for attachment in messageJson["attachments"]:
|
|
|
|
msg.attachments.add(MessageAttachment(
|
|
|
|
id: getIDFromJson(attachment["id"].getStr()),
|
|
|
|
filename: attachment["filename"].getStr(),
|
|
|
|
size: uint(attachment["size"].getInt()),
|
|
|
|
url: attachment["url"].getStr(),
|
|
|
|
proxyURL: attachment["proxy_url"].getStr(),
|
|
|
|
height: attachment["height"].getInt(),
|
|
|
|
width: attachment["width"].getInt()
|
|
|
|
))
|
|
|
|
|
|
|
|
for embed in messageJson["embeds"]:
|
|
|
|
msg.embeds.add(Embed(embedJson: embed))
|
|
|
|
|
|
|
|
if (messageJson.contains("reactions")):
|
|
|
|
for reaction in messageJson["reactions"]:
|
|
|
|
msg.reactions.add(Reaction(
|
|
|
|
count: uint(reaction["count"].getInt()),
|
|
|
|
me: reaction["me"].getBool(),
|
|
|
|
emoji: newEmoji(reaction["emoji"], msg.guildID)
|
|
|
|
))
|
2020-05-31 05:08:44 +00:00
|
|
|
|
2020-05-31 06:15:16 +00:00
|
|
|
if (messageJson.contains("activity")):
|
|
|
|
msg.activity = MessageActivity(`type`: MessageActivityType(messageJson["activity"]["type"].getInt()),
|
|
|
|
partyID: messageJson["activity"]["party_id"].getStr())
|
|
|
|
if (messageJson.contains("application")):
|
2020-05-31 05:08:44 +00:00
|
|
|
msg.application = MessageApplication(
|
2020-05-31 06:15:16 +00:00
|
|
|
id: getIDFromJson(messageJson["application"]["id"].getStr()),
|
|
|
|
coverImage: messageJson["application"]{"cover_image"}.getStr(),
|
|
|
|
description: messageJson["application"]["description"].getStr(),
|
|
|
|
icon: messageJson["application"]{"icon"}.getStr(),
|
|
|
|
name: messageJson["application"]["name"].getStr()
|
2020-05-31 05:08:44 +00:00
|
|
|
)
|
2020-05-31 06:15:16 +00:00
|
|
|
if (messageJson.contains("message_reference")):
|
2020-05-31 05:08:44 +00:00
|
|
|
msg.messageReference = MessageReference(
|
2020-05-31 06:15:16 +00:00
|
|
|
messageID: getIDFromJson(messageJson["message_reference"]{"message_id"}.getStr()),
|
|
|
|
channelID: getIDFromJson(messageJson["message_reference"]["channel_id"].getStr()),
|
|
|
|
guildID: getIDFromJson(messageJson["message_reference"]{"guild_id"}.getStr()),
|
2020-05-31 05:08:44 +00:00
|
|
|
)
|
|
|
|
|
2020-06-18 20:31:51 +00:00
|
|
|
return msg
|
|
|
|
|
|
|
|
proc addReaction*(message: Message, emoji: Emoji) {.async.} =
|
|
|
|
## Create a reaction for the message. This endpoint requires the
|
|
|
|
## `READ_MESSAGE_HISTORY` permission to be present on the current
|
|
|
|
## user. Additionally, if nobody else has reacted to the message
|
|
|
|
## using this emoji, this endpoint requires the 'ADD_REACTIONS'
|
|
|
|
## permission to be present on the current user.
|
2020-06-18 20:45:31 +00:00
|
|
|
##
|
|
|
|
## See also:
|
2020-06-18 21:12:00 +00:00
|
|
|
## * `removeReaction<#removeReaction,Message,Emoji>`_
|
2020-06-18 20:31:51 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/" & emoji.toUrlEncoding() & "/@me"), HttpPut, defaultHeaders(),
|
|
|
|
message.channelID, RateLimitBucketType.channel)
|
|
|
|
|
2020-06-18 20:45:31 +00:00
|
|
|
proc removeReaction*(message: Message, emoji: Emoji) {.async.} =
|
|
|
|
## Delete a reaction the bot user has made for the message.
|
2020-06-18 21:12:00 +00:00
|
|
|
##
|
|
|
|
## See also:
|
|
|
|
## * `addReaction<#addReaction,Message,Emoji>`_
|
|
|
|
## * `removeUserReaction<#removeUserReaction,Message,Emoji,User>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message,Emoji>`_
|
2020-06-18 20:45:31 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/" & emoji.toUrlEncoding() & "/@me"), HttpDelete, defaultHeaders(),
|
|
|
|
message.channelID, RateLimitBucketType.channel)
|
|
|
|
|
|
|
|
proc removeUserReaction*(message: Message, emoji: Emoji, user: User) {.async.} =
|
|
|
|
## Deletes another user's reaction. This endpoint requires the
|
|
|
|
## `MANAGE_MESSAGES` permission to be present on the current user
|
2020-06-18 21:12:00 +00:00
|
|
|
##
|
|
|
|
## See also:
|
|
|
|
## * `addReaction<#addReaction,Message,Emoji>`_
|
|
|
|
## * `removeReaction<#removeReaction,Message,Emoji>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message,Emoji>`_
|
2020-06-18 20:45:31 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/" & emoji.toUrlEncoding() & "/" & $user.id), HttpDelete, defaultHeaders(),
|
|
|
|
message.channelID, RateLimitBucketType.channel)
|
|
|
|
|
|
|
|
type ReactantsGetRequest* = object
|
|
|
|
## Use this type to get a messages's reactants by setting
|
|
|
|
## some of the fields.
|
|
|
|
## You can only set one of `before` and `after`.
|
|
|
|
before*: Option[snowflake]
|
|
|
|
after*: Option[snowflake]
|
|
|
|
limit*: Option[int]
|
|
|
|
|
|
|
|
proc getReactants*(message: Message, emoji: Emoji, request: ReactantsGetRequest): seq[User] =
|
|
|
|
## Get a list of users that reacted with this emoji.
|
|
|
|
|
|
|
|
var url: string = endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/" & emoji.toUrlEncoding())
|
|
|
|
|
|
|
|
# Raise some exceptions to make sure the user doesn't
|
|
|
|
# try to set more than one of these fields
|
|
|
|
if (request.before.isSome):
|
|
|
|
url = url & "before=" & $request.before.get()
|
|
|
|
|
|
|
|
if (request.after.isSome):
|
|
|
|
if (request.before.isSome):
|
|
|
|
raise newException(Defect, "You cannot get before and after a message! Choose one...")
|
|
|
|
url = url & "after=" & $request.after.get()
|
|
|
|
|
|
|
|
if (request.limit.isSome):
|
|
|
|
# Add the `&` for the url if something else is set.
|
|
|
|
if (request.before.isSome or request.after.isSome):
|
|
|
|
url = url & "&"
|
|
|
|
|
|
|
|
url = url & "limit=" & $request.limit.get()
|
|
|
|
|
|
|
|
let json = sendRequest(url, HttpGet, defaultHeaders(), message.channelID,
|
|
|
|
RateLimitBucketType.channel)
|
|
|
|
|
|
|
|
for user in json:
|
|
|
|
result.add(newUser(user))
|
|
|
|
|
2020-06-18 21:12:00 +00:00
|
|
|
proc removeAllReactions*(message: Message) {.async.} =
|
2020-06-18 20:45:31 +00:00
|
|
|
## Deletes all reactions on a message. This endpoint requires the
|
|
|
|
## `MANAGE_MESSAGES` permission to be present on the current user.
|
2020-06-18 21:12:00 +00:00
|
|
|
##
|
|
|
|
## See also:
|
|
|
|
## * `addReaction<#addReaction,Message,Emoji>`_
|
|
|
|
## * `removeReaction<#removeReaction,Message,Emoji>`_
|
|
|
|
## * `removeUserReaction<#removeUserReaction,Message,Emoji,User>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message,Emoji>`_
|
2020-06-18 20:45:31 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/"), HttpDelete, defaultHeaders(), message.channelID, RateLimitBucketType.channel)
|
|
|
|
|
2020-06-18 21:12:00 +00:00
|
|
|
proc removeAllReactions*(message: Message, emoji: Emoji) {.async.} =
|
2020-06-18 20:45:31 +00:00
|
|
|
## Deletes all the reactions for a given emoji on a message. This
|
|
|
|
## endpoint requires the `MANAGE_MESSAGES` permission to be present
|
|
|
|
## on the current user.
|
2020-06-18 21:12:00 +00:00
|
|
|
##
|
|
|
|
## See also:
|
|
|
|
## * `addReaction<#addReaction,Message,Emoji>`_
|
|
|
|
## * `removeReaction<#removeReaction,Message,Emoji>`_
|
|
|
|
## * `removeUserReaction<#removeUserReaction,Message,Emoji,User>`_
|
|
|
|
## * `removeAllReactions<#removeAllReactions,Message>`_
|
2020-06-18 20:45:31 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id &
|
|
|
|
"/reactions/" & emoji.toUrlEncoding()), HttpDelete, defaultHeaders(), message.channelID,
|
|
|
|
RateLimitBucketType.channel)
|
|
|
|
|
2020-06-18 20:31:51 +00:00
|
|
|
#TODO: Embeds and maybe flags?
|
|
|
|
proc editMessage*(message: Message, content: string): Future[Message] {.async.} =
|
2020-06-18 20:46:22 +00:00
|
|
|
## Edit a previously sent message.
|
2020-06-18 20:31:51 +00:00
|
|
|
let jsonBody = %*{"content": content}
|
|
|
|
return newMessage(sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id),
|
|
|
|
HttpPatch, defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})),
|
|
|
|
message.channelID, RateLimitBucketType.channel, jsonBody))
|
|
|
|
|
2020-06-18 20:45:31 +00:00
|
|
|
proc deleteMessage*(message: Message) {.async.} =
|
2020-06-18 20:31:51 +00:00
|
|
|
## Delete a message. If operating on a guild channel and trying to delete
|
|
|
|
## a message that was not sent by the current user, this endpoint requires
|
|
|
|
## the `MANAGE_MESSAGES` permission.
|
2020-06-18 21:12:00 +00:00
|
|
|
##
|
|
|
|
## See also:
|
|
|
|
## * `deleteMessage<#deleteMessage,Message>`_
|
2020-06-18 20:31:51 +00:00
|
|
|
discard sendRequest(endpoint("/channels/" & $message.channelID & "/messages/" & $message.id),
|
|
|
|
HttpDelete, defaultHeaders(), message.channelID, RateLimitBucketType.channel)
|