feat: add get_user_harvest & create_user_harvest
Also adds /types/entities/harvest.rs, types for Harvest
This commit is contained in:
parent
9d847906be
commit
87aad461fd
|
@ -12,9 +12,10 @@ use crate::{
|
|||
instance::{ChorusUser, Instance},
|
||||
ratelimiter::ChorusRequest,
|
||||
types::{
|
||||
DeleteDisableUserSchema, GetPomeloEligibilityReturn, GetPomeloSuggestionsReturn,
|
||||
GetRecentMentionsSchema, GetUserProfileSchema, LimitType, PublicUser, Snowflake, User,
|
||||
UserModifyProfileSchema, UserModifySchema, UserProfile, UserProfileMetadata, UserSettings,
|
||||
CreateUserHarvestSchema, DeleteDisableUserSchema, GetPomeloEligibilityReturn,
|
||||
GetPomeloSuggestionsReturn, GetRecentMentionsSchema, GetUserProfileSchema, Harvest,
|
||||
HarvestBackendType, LimitType, PublicUser, Snowflake, User, UserModifyProfileSchema,
|
||||
UserModifySchema, UserProfile, UserProfileMetadata, UserSettings,
|
||||
VerifyUserEmailChangeResponse, VerifyUserEmailChangeSchema,
|
||||
},
|
||||
};
|
||||
|
@ -410,6 +411,100 @@ impl ChorusUser {
|
|||
|
||||
chorus_request.handle_request_as_result(self).await
|
||||
}
|
||||
|
||||
/// If it exists, returns the most recent [Harvest] (personal data harvest request).
|
||||
///
|
||||
/// To create a new [Harvest], see [Self::create_harvest].
|
||||
///
|
||||
/// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting)
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#get-user-harvest>
|
||||
pub async fn get_harvest(&mut self) -> ChorusResult<Option<Harvest>> {
|
||||
let request = Client::new()
|
||||
.get(format!(
|
||||
"{}/users/@me/harvest",
|
||||
self.belongs_to.read().unwrap().urls.api,
|
||||
))
|
||||
.header("Authorization", self.token());
|
||||
|
||||
let chorus_request = ChorusRequest {
|
||||
request,
|
||||
limit_type: LimitType::default(),
|
||||
};
|
||||
|
||||
// Manual handling, because a 204 with no harvest is a success state
|
||||
// TODO: Maybe make this a method on ChorusRequest if we need it a lot
|
||||
let response = chorus_request.send_request(self).await?;
|
||||
log::trace!("Got response: {:?}", response);
|
||||
|
||||
if response.status() == http::StatusCode::NO_CONTENT {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let response_text = match response.text().await {
|
||||
Ok(string) => string,
|
||||
Err(e) => {
|
||||
return Err(ChorusError::InvalidResponse {
|
||||
error: format!(
|
||||
"Error while trying to process the HTTP response into a String: {}",
|
||||
e
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let object = match serde_json::from_str::<Harvest>(&response_text) {
|
||||
Ok(object) => object,
|
||||
Err(e) => {
|
||||
return Err(ChorusError::InvalidResponse {
|
||||
error: format!(
|
||||
"Error while trying to deserialize the JSON response into requested type T: {}. JSON Response: {}",
|
||||
e, response_text
|
||||
),
|
||||
})
|
||||
}
|
||||
};
|
||||
Ok(Some(object))
|
||||
}
|
||||
|
||||
/// Creates a personal data harvest request ([Harvest]) for the current user.
|
||||
///
|
||||
/// To fetch the latest existing harvest, see [Self::get_harvest].
|
||||
///
|
||||
/// Invalid options in the backends array are ignored.
|
||||
///
|
||||
/// If the array is empty (after ignoring), it requests all [HarvestBackendType]s.
|
||||
///
|
||||
/// As of 2024/08/09, Spacebar does not yet implement this endpoint. (Or data harvesting)
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#create-user-harvest>
|
||||
pub async fn create_harvest(
|
||||
&mut self,
|
||||
backends: Vec<HarvestBackendType>,
|
||||
) -> ChorusResult<Harvest> {
|
||||
let schema = if backends.is_empty() {
|
||||
CreateUserHarvestSchema { backends: None }
|
||||
} else {
|
||||
CreateUserHarvestSchema {
|
||||
backends: Some(backends),
|
||||
}
|
||||
};
|
||||
|
||||
let request = Client::new()
|
||||
.post(format!(
|
||||
"{}/users/@me/harvest",
|
||||
self.belongs_to.read().unwrap().urls.api,
|
||||
))
|
||||
.header("Authorization", self.token())
|
||||
.json(&schema);
|
||||
|
||||
let chorus_request = ChorusRequest {
|
||||
request,
|
||||
limit_type: LimitType::default(),
|
||||
};
|
||||
|
||||
chorus_request.deserialize_response(self).await
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
use crate::types::Snowflake;
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
use crate::gateway::Updateable;
|
||||
|
||||
// FIXME: Should this type be Composite?
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
|
||||
/// A user's data harvest.
|
||||
///
|
||||
/// # Reference
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#harvest-object>
|
||||
pub struct Harvest {
|
||||
pub harvest_id: Snowflake,
|
||||
/// The id of the user being harvested
|
||||
pub user_id: Snowflake,
|
||||
pub status: HarvestStatus,
|
||||
/// The time the harvest was created
|
||||
pub created_at: DateTime<Utc>,
|
||||
/// The time the harvest was last polled
|
||||
pub polled_at: Option<DateTime<Utc>>,
|
||||
/// The time the harvest was completed
|
||||
pub completed_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "client")]
|
||||
impl Updateable for Harvest {
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
fn id(&self) -> Snowflake {
|
||||
self.harvest_id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize_repr,
|
||||
Deserialize_repr,
|
||||
Debug,
|
||||
Default,
|
||||
Clone,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
Copy,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||
#[repr(u8)]
|
||||
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||
/// Current status of a [Harvest]
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#harvest-status> and <https://docs.discord.sex/resources/user#harvest-object>
|
||||
pub enum HarvestStatus {
|
||||
/// The harvest is queued and has not been started
|
||||
Queued = 0,
|
||||
/// The harvest is currently running / being processed
|
||||
Running = 1,
|
||||
/// The harvest has failed
|
||||
Failed = 2,
|
||||
/// The harvest has been completed successfully
|
||||
Completed = 3,
|
||||
#[default]
|
||||
Unknown = 4,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash, Copy, PartialOrd, Ord)]
|
||||
#[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
|
||||
/// A type of backend / service a harvest can be requested for.
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#harvest-backend-type> and <https://support.discord.com/hc/en-us/articles/360004957991-Your-Discord-Data-Package>
|
||||
pub enum HarvestBackendType {
|
||||
/// All account information;
|
||||
Accounts,
|
||||
/// Actions the user has taken;
|
||||
///
|
||||
/// Represented as "Your Activity" in the discord client
|
||||
Analytics,
|
||||
/// First-party embedded activity information;
|
||||
///
|
||||
/// e.g.: Chess in the Park, Checkers in the Park, Poker Night 2.0;
|
||||
/// Sketch Heads, Watch Together, Letter League, Land-io, Know What I Meme
|
||||
Activities,
|
||||
/// The user's messages
|
||||
Messages,
|
||||
/// Official Discord programes;
|
||||
///
|
||||
/// e.g.: Partner, HypeSquad, Verified Server
|
||||
Programs,
|
||||
/// Guilds the user is a member of;
|
||||
Servers,
|
||||
}
|
|
@ -11,6 +11,7 @@ pub use config::*;
|
|||
pub use emoji::*;
|
||||
pub use guild::*;
|
||||
pub use guild_member::*;
|
||||
pub use harvest::*;
|
||||
pub use integration::*;
|
||||
pub use invite::*;
|
||||
pub use message::*;
|
||||
|
@ -52,6 +53,7 @@ mod config;
|
|||
mod emoji;
|
||||
mod guild;
|
||||
mod guild_member;
|
||||
mod harvest;
|
||||
mod integration;
|
||||
mod invite;
|
||||
mod message;
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::collections::HashMap;
|
|||
use chrono::NaiveDate;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Snowflake, ThemeColors};
|
||||
use crate::types::{HarvestBackendType, Snowflake, ThemeColors};
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -218,7 +218,7 @@ pub struct GetUserProfileSchema {
|
|||
///
|
||||
/// See <https://docs.discord.sex/resources/user#get-pomelo-suggestions>
|
||||
pub(crate) struct GetPomeloSuggestionsReturn {
|
||||
pub username: String
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
|
@ -226,7 +226,7 @@ pub(crate) struct GetPomeloSuggestionsReturn {
|
|||
///
|
||||
/// See <https://docs.discord.sex/resources/user#get-pomelo-eligibility>
|
||||
pub(crate) struct GetPomeloEligibilityReturn {
|
||||
pub taken: bool
|
||||
pub taken: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -257,3 +257,13 @@ pub struct GetRecentMentionsSchema {
|
|||
/// If unset the server assumes true
|
||||
pub everyone: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
/// Internal type for the [crate::instance::ChorusUser::create_harvest] endpoint.
|
||||
// (koza): imo it's nicer if the user can just pass a vec, instead of having to bother with
|
||||
// a specific type
|
||||
///
|
||||
/// See <https://docs.discord.sex/resources/user#create-user-harvest>
|
||||
pub(crate) struct CreateUserHarvestSchema {
|
||||
pub backends: Option<Vec<HarvestBackendType>>,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue