chorus 0.20.0

A library for interacting with multiple Spacebar-compatible Instances at once.
Documentation
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use reqwest::Client;
use serde_json::to_string;

use crate::types::{AddChannelRecipientSchema, ModifyChannelPositionsSchema};
use crate::{
    errors::{ChorusError, ChorusResult},
    instance::ChorusUser,
    ratelimiter::ChorusRequest,
    types::{
        Channel, ChannelModifySchema, GetChannelMessagesSchema, LimitType, Message, Snowflake,
    },
};

impl Channel {
    /// Retrieves a channel from the server.
    ///
    /// # Reference
    /// See <https://docs.discord.food/resources/channel#get-channel>
    pub async fn get(user: &mut ChorusUser, channel_id: Snowflake) -> ChorusResult<Channel> {
        let chorus_request = ChorusRequest {
            request: Client::new().get(format!(
                "{}/channels/{}",
                user.belongs_to.read().unwrap().urls.api.clone(),
                channel_id
            )),
            limit_type: LimitType::Channel(channel_id),
        }
        .with_headers_for(user);

        chorus_request.send_and_deserialize_response::<Channel>(user).await
    }

    /// Deletes self.
    ///
    /// Requires the [`MANAGE_CHANNELS`](crate::types::PermissionFlags::MANAGE_CHANNELS) permission in a guild, or
    /// the [`MANAGE_THREADS`](crate::types::PermissionFlags::MANAGE_THREADS) permission if the channel is a thread.
    ///
    /// # Reference
    /// See <https://docs.discord.food/resources/channel#delete-channel>
    pub async fn delete(
        self,
        audit_log_reason: Option<String>,
        user: &mut ChorusUser,
    ) -> ChorusResult<()> {
        let url = format!(
            "{}/channels/{}",
            user.belongs_to.read().unwrap().urls.api,
            self.id,
        );

        let request = ChorusRequest {
            request: Client::new().delete(url),
            limit_type: LimitType::Channel(self.id),
        }
        .with_maybe_audit_log_reason(audit_log_reason)
        .with_headers_for(user);

        request.send_and_handle_as_result(user).await
    }

    /// Modifies a channel with the provided data.
    /// Returns the new Channel.
    ///
    /// Requires the [`MANAGE_CHANNELS`](crate::types::PermissionFlags::MANAGE_CHANNELS) permission in a guild.
    ///
    /// If modifying permission overwrites, the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission is required.
    /// Only permissions you have in the guild or parent channel (if applicable) can be allowed/denied
    /// (unless you have a [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) overwrite in the channel).
    ///
    /// If modifying a thread and setting `archived` to `false`, when `locked` is also `false`, only the [`SEND_MESSAGES`](crate::types::PermissionFlags::SEND_MESSAGES) permission is required.
    /// Otherwise, requires the [`MANAGE_THREADS`](crate::types::PermissionFlags::MANAGE_THREADS) permission. Requires the thread to have `archived` set to `false` or be set to `false` in the request.
    ///
    /// # Reference
    /// See <https://docs.discord.food/resources/channel#modify-channel>
    pub async fn modify(
        &self,
        modify_data: ChannelModifySchema,
        audit_log_reason: Option<String>,
        user: &mut ChorusUser,
    ) -> ChorusResult<Channel> {
        let channel_id = self.id;
        let url = format!(
            "{}/channels/{}",
            user.belongs_to.read().unwrap().urls.api,
            channel_id
        );

        let request = ChorusRequest {
            request: Client::new().patch(url).json(&modify_data),
            limit_type: LimitType::Channel(channel_id),
        }
        .with_maybe_audit_log_reason(audit_log_reason)
        .with_headers_for(user);

        request.send_and_deserialize_response::<Channel>(user).await
    }

    /// Fetches recent messages from a channel.
    ///
    /// If operating on a guild channel, this endpoint requires the [`VIEW_CHANNEL`](crate::types::PermissionFlags::VIEW_CHANNEL) permission.
    ///
    /// If the user is missing the [`READ_MESSAGE_HISTORY`](crate::types::PermissionFlags::READ_MESSAGE_HISTORY) permission,
    /// this method returns an empty list.
    ///
    /// # Reference
    /// See <https://docs.discord.food/resources/message#get-messages>
    pub async fn messages(
        range: GetChannelMessagesSchema,
        channel_id: Snowflake,
        user: &mut ChorusUser,
    ) -> Result<Vec<Message>, ChorusError> {
        let url = format!(
            "{}/channels/{}/messages",
            user.belongs_to.read().unwrap().urls.api,
            channel_id
        );

        let mut chorus_request = ChorusRequest {
            request: Client::new().get(url),
            limit_type: Default::default(),
        }
        .with_headers_for(user);

        chorus_request.request = chorus_request.request.query(&range);

        chorus_request
            .send_and_deserialize_response::<Vec<Message>>(user)
            .await
    }

    /// Adds a recipient to a group DM.
    ///
    /// # Reference:
    /// See <https://docs.discord.food/resources/channel#add-channel-recipient>
    pub async fn add_channel_recipient(
        &self,
        recipient_id: Snowflake,
        user: &mut ChorusUser,
        add_channel_recipient_schema: Option<AddChannelRecipientSchema>,
    ) -> ChorusResult<()> {
        let mut request = Client::new().put(format!(
            "{}/channels/{}/recipients/{}",
            user.belongs_to.read().unwrap().urls.api,
            self.id,
            recipient_id
        ));

        if let Some(schema) = add_channel_recipient_schema {
            request = request.json(&schema);
        }

        ChorusRequest {
            request,
            limit_type: LimitType::Channel(self.id),
        }
        .with_headers_for(user)
        .send_and_handle_as_result(user)
        .await
    }

    /// Removes a recipient from a group DM.
    ///
    /// # Reference:
    /// See <https://docs.discord.food/resources/channel#remove-channel-recipient>
    pub async fn remove_channel_recipient(
        &self,
        recipient_id: Snowflake,
        user: &mut ChorusUser,
    ) -> ChorusResult<()> {
        let url = format!(
            "{}/channels/{}/recipients/{}",
            user.belongs_to.read().unwrap().urls.api,
            self.id,
            recipient_id
        );

        let request = ChorusRequest {
            request: Client::new().delete(url),
            limit_type: LimitType::Channel(self.id),
        }
        .with_headers_for(user);

        request.send_and_handle_as_result(user).await
    }

    /// Modifies the positions of a set of channel objects for the guild. Requires the `MANAGE_CHANNELS` permission.
    /// Only channels to be modified are required.
    ///
    /// # Reference:
    /// See <https://docs.discord.food/resources/channel#modify-guild-channel-positions>
    pub async fn modify_positions(
        schema: Vec<ModifyChannelPositionsSchema>,
        guild_id: Snowflake,
        user: &mut ChorusUser,
    ) -> ChorusResult<()> {
        let url = format!(
            "{}/guilds/{}/channels",
            user.belongs_to.read().unwrap().urls.api,
            guild_id
        );

        let request = ChorusRequest {
            request: Client::new().patch(url).json(&schema),
            limit_type: LimitType::Guild(guild_id),
        }
        .with_headers_for(user);

        request.send_and_handle_as_result(user).await
    }
}