diff --git a/src/grom.gleam b/src/grom.gleam index 8967877..83c2f1c 100644 --- a/src/grom.gleam +++ b/src/grom.gleam @@ -15953,3 +15953,203 @@ pub fn modify_message_response( ) -> Result(Message, RestError) { handle_response_bits(response, decode_with: message_decoder()) } + +/// Deleting others' messages requires the `AllowManagingMessages` permission. +pub fn delete_message_request( + token token: Token, + in_channel_with_id channel_id: Snowflake(Channel), + message_with_id message_id: Snowflake(Message), + reason reason: Option(String), +) -> Request(String) { + new_request( + token:, + to: "/channels/" + <> snowflake_to_string(channel_id) + <> "/messages/" + <> snowflake_to_string(message_id), + method: http.Delete, + ) + |> request_with_reason(reason) +} + +pub fn delete_message_response( + response: Response(String), +) -> Result(Nil, RestError) { + handle_no_content_response(response) +} + +/// Any messages older than 2 weeks will be rejected by Discord. +/// +/// You must provide between 2 and 100 messages. +/// +/// Requires the `AllowManagingMessages` permission. +pub fn bulk_delete_messages_request( + token token: Token, + in_channel_with_id channel_id: Snowflake(GuildChannel), + message_ids message_ids: List(Snowflake(Message)), + reason reason: Option(String), +) -> Request(String) { + let body = + [#("messages", json.array(message_ids, snowflake_to_json))] + |> json.object + |> json.to_string + + new_request( + token:, + to: "/channels/" + <> snowflake_to_string(channel_id) + <> "/messages/bulk-delete", + method: http.Post, + ) + |> request.set_body(body) + |> request_with_reason(reason) +} + +pub fn bulk_delete_messages_response( + response: Response(String), +) -> Result(Nil, RestError) { + handle_no_content_response(response) +} + +pub fn get_creation_timestamp(of snowflake: Snowflake(a)) -> Timestamp { + let milliseconds = + snowflake.id + // this is where the timestamp portion starts + |> int.bitwise_shift_right(22) + // discord epoch - 01/01/2015 00:00:00 UTC + // no snowflakes are older than that, so we add that number so it makes it into a unix timestamp + |> int.add(1_420_070_400_000) + + let seconds = milliseconds / 1000 + let nanoseconds = milliseconds * 1_000_000 + + timestamp.from_unix_seconds_and_nanoseconds(seconds:, nanoseconds:) +} + +pub opaque type GetChannelPinsOptions { + GetChannelPinsOptions(before: Option(Timestamp), limit: Int) +} + +/// Default limit is 50. +pub fn new_get_channel_pins_options() -> GetChannelPinsOptions { + GetChannelPinsOptions(None, 50) +} + +pub fn get_channel_pins_before( + options: GetChannelPinsOptions, + timestamp timestamp: Timestamp, +) -> GetChannelPinsOptions { + GetChannelPinsOptions(..options, before: Some(timestamp)) +} + +pub fn get_channel_pins_with_limit( + options: GetChannelPinsOptions, + limit: Int, +) -> GetChannelPinsOptions { + GetChannelPinsOptions(..options, limit:) +} + +fn get_channel_pins_options_to_query( + options: GetChannelPinsOptions, +) -> List(#(String, String)) { + [ + optional_to_string(options.before, "before", timestamp.to_rfc3339( + _, + duration.seconds(0), + )), + Ok(#("limit", int.to_string(options.limit))), + ] + |> list.filter_map(function.identity) +} + +/// Requires the `AllowViewingChannels` permission. +/// +/// Soft fails (returns 0 pins) if missing the `AllowReadingMessageHistory` permission. +pub fn get_channel_pins_request( + token token: Token, + channel_with_id channel_id: Snowflake(GuildChannel), + using options: GetChannelPinsOptions, +) -> Request(String) { + let query = options |> get_channel_pins_options_to_query + + new_request( + token:, + to: "/channels/" <> snowflake_to_string(channel_id) <> "/messages/pins", + method: http.Get, + ) + |> request.set_query(query) +} + +pub type GetChannelPinsResponse { + GetChannelPinsResponse(pins: List(MessagePin), has_more: Bool) +} + +fn get_channel_pins_response_decoder() -> Decoder(GetChannelPinsResponse) { + use pins <- decode.field("items", decode.list(message_pin_decoder())) + use has_more <- decode.field("has_more", decode.bool) + decode.success(GetChannelPinsResponse(pins:, has_more:)) +} + +pub type MessagePin { + MessagePin(pinned_timestamp: Timestamp, message: Message) +} + +fn message_pin_decoder() -> Decoder(MessagePin) { + use pinned_timestamp <- decode.field("pinned_at", rfc3339_decoder()) + use message <- decode.field("message", message_decoder()) + decode.success(MessagePin(pinned_timestamp:, message:)) +} + +pub fn get_channel_pins_response( + response: Response(String), +) -> Result(GetChannelPinsResponse, RestError) { + handle_response(response, decode_with: get_channel_pins_response_decoder()) +} + +/// Requires the `AllowPinningMessages` permission. +pub fn pin_message_request( + token token: Token, + in_channel_with_id channel_id: Snowflake(GuildChannel), + message_with_id message_id: Snowflake(Message), + reason reason: Option(String), +) -> Request(String) { + new_request( + token:, + to: "/channels/" + <> snowflake_to_string(channel_id) + <> "/messages/pins/" + <> snowflake_to_string(message_id), + method: http.Put, + ) + |> request_with_reason(reason) +} + +pub fn pin_message_response( + response: Response(String), +) -> Result(Nil, RestError) { + handle_no_content_response(response) +} + +/// Requires the `AllowPinningMessages` permission. +pub fn unpin_message_request( + token token: Token, + in_channel_with_id channel_id: Snowflake(GuildChannel), + message_with_id message_id: Snowflake(Message), + reason reason: Option(String), +) -> Request(String) { + new_request( + token:, + to: "/channels/" + <> snowflake_to_string(channel_id) + <> "/messages/pins/" + <> snowflake_to_string(message_id), + method: http.Delete, + ) + |> request_with_reason(reason) +} + +pub fn unpin_message_response( + response: Response(String), +) -> Result(Nil, RestError) { + handle_no_content_response(response) +}