diff --git a/src/client.nim b/src/client.nim index aa3eb59..f589a69 100644 --- a/src/client.nim +++ b/src/client.nim @@ -169,9 +169,6 @@ registerEventListener(EventType.evtMessageCreate, proc(bEvt: BaseEvent) = let messages = channel.getMessages(MessagesGetRequest(limit: some(amount), before: some(event.message.id))) discard channel.bulkDeleteMessages(messages) elif (event.message.content.startsWith("?reactToMessage")): - var guild: Guild - discard guild.createGuildRole(name = some("Gamer Role"), color = some(0xff0000)) - var channel: Channel = event.message.getMessageChannel(event.client.cache) if (channel != nil): let emojis = @[newEmoji("⏮️"), newEmoji("⬅️"), newEmoji("⏹️"), newEmoji("➡️"), newEmoji("⏭️")] diff --git a/src/emoji.nim b/src/emoji.nim index 1970665..8776c7d 100644 --- a/src/emoji.nim +++ b/src/emoji.nim @@ -1,21 +1,23 @@ -import json, discordobject, nimcordutils, user, httpcore, strutils, uri +import json, discordobject, nimcordutils, user, httpcore, strutils, uri, strformat, asyncdispatch type Emoji* = ref object of DiscordObject name*: string roles*: seq[snowflake] user*: User - requireColons: bool - managed: bool - animated: bool - available: bool + requireColons*: bool + managed*: bool + animated*: bool + available*: bool + guildID*: snowflake -proc newEmoji*(json: JsonNode): Emoji = +proc newEmoji*(json: JsonNode, guild: snowflake): Emoji = ## Construct an emoji with json. ## This shouldn't really be used by the user, only internal use. result = Emoji( id: getIDFromJson(json["id"].getStr()), - name: json["name"].getStr() + name: json["name"].getStr(), + guildID: guild ) if (json.contains("roles")): @@ -72,4 +74,24 @@ proc toUrlEncoding*(emoji: Emoji): string = ## Converts the `Emoji` to be used in a url. ## Not needed for users, only for internal ## library use. - return encodeUrl($emoji, true) \ No newline at end of file + return encodeUrl($emoji, true) + +proc modifyEmoji*(emoji: var Emoji, name: string, roles: seq[snowflake] = @[]): Future[Emoji] {.async.} = + ## Modify the given emoji. Requires the `MANAGE_EMOJIS` permission. + ## Changes will be reflected in given `emoji`. + var jsonBody = %* { + "name": name, + "roles": parseJson(($roles).substr(1)) + } + + emoji.name = name + emoji.roles = roles + + return newEmoji(sendRequest(endpoint(fmt("/guilds/{emoji.guildID}/emojis/{emoji.id}")), HttpPatch, + defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})), + emoji.guildID, RateLimitBucketType.guild, jsonBody), emoji.guildID) + +proc deleteEmoji*(emoji: Emoji) {.async.} = + ## Delete the given emoji. Requires the `MANAGE_EMOJIS` permission. + discard sendRequest(endpoint(fmt("/guilds/{emoji.guildID}/emojis/{emoji.id}")), HttpDelete, + defaultHeaders(), emoji.guildID, RateLimitBucketType.guild) \ No newline at end of file diff --git a/src/guild.nim b/src/guild.nim index 9f6ea71..b4b1aa8 100644 --- a/src/guild.nim +++ b/src/guild.nim @@ -179,7 +179,7 @@ proc newGuild*(json: JsonNode): Guild {.inline.} = for role in json["roles"]: g.roles.add(newRole(role, g.id)) for emoji in json["emojis"]: - g.emojis.add(newEmoji(emoji)) + g.emojis.add(newEmoji(emoji, g.id)) #TODO features if (json.contains("widget_enabled")): g.widgetEnabled = json["widget_enabled"].getBool() @@ -194,7 +194,7 @@ proc newGuild*(json: JsonNode): Guild {.inline.} = #TODO: voice_states if (json.contains("members")): for member in json["members"]: - g.members.insert(newGuildMember(member, g.id)) + g.members.insert(newGuildMember(member, g.roles, g.id)) if (json.contains("channels")): for channel in json["channels"]: g.channels.insert(newChannel(channel)) @@ -317,7 +317,7 @@ proc getGuildPreview*(guild: Guild): GuildPreview = ) for emoji in json["emojis"]: - result.emojis.add(newEmoji(emoji)) + result.emojis.add(newEmoji(emoji, guild.id)) for feature in json["features"]: result.features.add(feature.getStr()) @@ -491,7 +491,7 @@ proc getGuildMember*(guild: var Guild, memberID: snowflake): GuildMember = return member result = newGuildMember(sendRequest(endpoint(fmt("/guilds/{guild.id}/members/{memberID}")), - HttpPatch, defaultHeaders(), guild.id, RateLimitBucketType.guild), guild.id) + HttpPatch, defaultHeaders(), guild.id, RateLimitBucketType.guild), guild.roles, guild.id) guild.members.add(result) # Would this endpoint be worth adding? https://discord.com/developers/docs/resources/guild#list-guild-members @@ -818,4 +818,40 @@ proc getGuildWidgetImage*(guild: Guild, style: GuildWidgetStyle): string = of (GuildWidgetStyle.guildWidgetStyleBanner3): result &= "?style=banner3" of (GuildWidgetStyle.guildWidgetStyleBanner4): - result &= "?style=banner4" \ No newline at end of file + result &= "?style=banner4" + +proc requestEmojis*(guild: Guild): seq[Emoji] = + ## Request all guild emojis via Discord's REST API + ## Only use this if, for some reason, guild.emojis is inaccurate! + ## + ## Also updates the guild's emojis when called. + let json = sendRequest(endpoint("/guilds/" & $guild.id & "/emojis"), HttpGet, + defaultHeaders(), guild.id, RateLimitBucketType.guild) + + for emoji in json: + result.add(newEmoji(emoji, guild.id)) + guild.emojis = result + +proc getEmoji*(guild: Guild, emojiID: snowflake): Emoji = + ## Returns a guild's emoji with `emojiID`. + ## If the emoji isn't found in `guild.emojis` then it will request on + ## from the Discord REST API. + for emoji in guild.emojis: + if emoji.id == emojiID: + return emoji + + return newEmoji(sendRequest(endpoint("/guilds/{guild.id}/emojis/{emojiID}"), HttpGet, + defaultHeaders(), guild.id, RateLimitBucketType.guild), guild.id) + +proc createEmoji*(guild: Guild, name: string, image: Image, roles: seq[snowflake] = @[]): Future[Emoji] {.async.} = + ## Create a new emoji for the guild. Requires the `MANAGE_EMOJIS` permission. + var jsonBody = %* { + "name": name, + "image": image.imageToDataURI() + } + + jsonBody.add(parseJson(($roles).substr(1))) + + return newEmoji(sendRequest(endpoint(fmt("/guilds/{guild.id}/emojis")), HttpPost, + defaultHeaders(newHttpHeaders({"Content-Type": "application/json"})), + guild.id, RateLimitBucketType.guild, jsonBody), guild.id) \ No newline at end of file diff --git a/src/member.nim b/src/member.nim index e8ee864..c671c83 100644 --- a/src/member.nim +++ b/src/member.nim @@ -11,9 +11,9 @@ type GuildMember* = ref object of DiscordObject mute*: bool ## Whether the user is muted in voice channels. guildID*: snowflake ## The guild this member is in. -proc newGuildMember*(json: JsonNode, guild: snowflake): GuildMember {.inline.} = +proc newGuildMember*(json: JsonNode, guildRoles: seq[Role], guild: snowflake): GuildMember {.inline.} = ## Construct a GuildMember using json. - var member = GuildMember( + result = GuildMember( nick: json{"nick"}.getStr(), #roles: seq[Role] joinedAt: json["joined_at"].getStr(), @@ -24,12 +24,17 @@ proc newGuildMember*(json: JsonNode, guild: snowflake): GuildMember {.inline.} = ) if (json.contains("user")): - member.user = newUser(json["user"]) + result.user = newUser(json["user"]) - for role in json: - member.roles.add(newRole(role, member.guildID)) + # Add roles + if (json.contains("roles") and guildRoles.len > 0): + var roleIDs: seq[snowflake] + for role in json["roles"]: + roleIDs.add(getIDFromJson(role.getStr())) - return member + for role in guildRoles: + if (roleIDs.contains(role.id)): + result.roles.add(role) type GuildMemberModify* = ref object nick: Option[string] diff --git a/src/message.nim b/src/message.nim index aab5909..c563407 100644 --- a/src/message.nim +++ b/src/message.nim @@ -94,7 +94,7 @@ proc newMessage*(messageJson: JsonNode): Message = if (messageJson.contains("author")): msg.author = newUser(messageJson["author"]) if (messageJson.contains("member")): - msg.member = newGuildMember(messageJson["member"], msg.guildID) + msg.member = newGuildMember(messageJson["member"], @[], msg.guildID) if (messageJson.contains("mentions")): let mentionsJson = messageJson["mentions"].getElems() diff --git a/src/role.nim b/src/role.nim index 70ae8c2..dfb3450 100644 --- a/src/role.nim +++ b/src/role.nim @@ -11,18 +11,28 @@ type Role* = ref object of DiscordObject guildID*: snowflake proc newRole*(json: JsonNode, guild: snowflake): Role = - result = Role( - id: getIDFromJson(json["id"].getStr()), + echo "ROLE JSON: ", json + result = Role() + result.id = getIDFromJson(json["id"].getStr()) + result.name = json["name"].getStr() + result.color = uint(json["color"].getInt()) + result.hoist = json["hoist"].getBool() + result.position = uint(json["position"].getInt()) + result.managed = json["managed"].getBool() + result.mentionable = json["mentionable"].getBool() + result.guildID = guild + #[ id: getIDFromJson(json["id"].getStr()), name: json["name"].getStr(), color: uint(json["color"].getInt()), hoist: json["hoist"].getBool(), position: uint(json["position"].getInt()), managed: json["managed"].getBool(), mentionable: json["mentionable"].getBool(), - guildID: guild, - permissions: newPermissions(result.id, PermissionType.permTypeRole, + guildID: guild + ) ]# + + result.permissions = newPermissions(result.id, PermissionType.permTypeRole, uint(json["permissions"].getInt())) - ) proc modifyGuildRole*(role: var Role, name: Option[string] = none(string), permissions: Option[Permissions] = none(Permissions), color: Option[int] = none(int), hoist: Option[bool] = none(bool), mentionable: Option[bool] = none(bool)): Future[Role] {.async.} =