diff --git a/apps/labrinth/src/models/v2/projects.rs b/apps/labrinth/src/models/v2/projects.rs index 17c068f5..ef4c4845 100644 --- a/apps/labrinth/src/models/v2/projects.rs +++ b/apps/labrinth/src/models/v2/projects.rs @@ -306,7 +306,8 @@ pub struct LegacyVersion { pub featured: bool, pub name: String, pub version_number: String, - pub changelog: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub changelog: Option, pub changelog_url: Option, pub date_published: DateTime, pub downloads: u32, diff --git a/apps/labrinth/src/models/v3/projects.rs b/apps/labrinth/src/models/v3/projects.rs index d75b0846..0ccc193b 100644 --- a/apps/labrinth/src/models/v3/projects.rs +++ b/apps/labrinth/src/models/v3/projects.rs @@ -661,7 +661,8 @@ pub struct Version { /// Games for which this version is compatible with, extracted from Loader/Project types pub games: Vec, /// The changelog for this version of the project. - pub changelog: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub changelog: Option, /// The date that this version was published. pub date_published: DateTime, @@ -714,7 +715,7 @@ impl From for Version { version_number: v.version_number, project_types: data.project_types, games: data.games, - changelog: v.changelog, + changelog: Some(v.changelog), date_published: v.date_published, downloads: v.downloads as u32, version_type: match v.version_type.as_str() { diff --git a/apps/labrinth/src/routes/v2/versions.rs b/apps/labrinth/src/routes/v2/versions.rs index 6e91f8a3..0219ec1d 100644 --- a/apps/labrinth/src/routes/v2/versions.rs +++ b/apps/labrinth/src/routes/v2/versions.rs @@ -37,6 +37,12 @@ pub struct VersionListFilters { pub version_type: Option, pub limit: Option, pub offset: Option, + #[serde(default = "default_true")] + pub include_changelog: bool, +} + +fn default_true() -> bool { + true } #[get("version")] @@ -95,6 +101,7 @@ pub async fn version_list( version_type: filters.version_type, limit: filters.limit, offset: filters.offset, + include_changelog: filters.include_changelog, }; let response = v3::versions::version_list( @@ -153,6 +160,8 @@ pub async fn version_project_get( #[derive(Serialize, Deserialize)] pub struct VersionIds { pub ids: String, + #[serde(default = "default_true")] + pub include_changelog: bool, } #[get("versions")] @@ -163,7 +172,10 @@ pub async fn versions_get( redis: web::Data, session_queue: web::Data, ) -> Result { - let ids = v3::versions::VersionIds { ids: ids.ids }; + let ids = v3::versions::VersionIds { + ids: ids.ids, + include_changelog: ids.include_changelog, + }; let response = v3::versions::versions_get( req, web::Query(ids), diff --git a/apps/labrinth/src/routes/v3/version_creation.rs b/apps/labrinth/src/routes/v3/version_creation.rs index d3726df3..69cbc8bc 100644 --- a/apps/labrinth/src/routes/v3/version_creation.rs +++ b/apps/labrinth/src/routes/v3/version_creation.rs @@ -436,7 +436,7 @@ async fn version_create_inner( version_number: builder.version_number.clone(), project_types: all_project_types, games: all_games, - changelog: builder.changelog.clone(), + changelog: Some(builder.changelog.clone()), date_published: Utc::now(), downloads: 0, version_type: version_data.release_channel, diff --git a/apps/labrinth/src/routes/v3/versions.rs b/apps/labrinth/src/routes/v3/versions.rs index cdca2407..4e906ed8 100644 --- a/apps/labrinth/src/routes/v3/versions.rs +++ b/apps/labrinth/src/routes/v3/versions.rs @@ -121,6 +121,12 @@ pub async fn version_project_get_helper( #[derive(Serialize, Deserialize)] pub struct VersionIds { pub ids: String, + #[serde(default = "default_true")] + pub include_changelog: bool, +} + +fn default_true() -> bool { + true } pub async fn versions_get( @@ -150,10 +156,16 @@ pub async fn versions_get( .map(|x| x.1) .ok(); - let versions = + let mut versions = filter_visible_versions(versions_data, &user_option, &pool, &redis) .await?; + if !ids.include_changelog { + for version in &mut versions { + version.changelog = None; + } + } + Ok(HttpResponse::Ok().json(versions)) } @@ -715,6 +727,8 @@ pub struct VersionListFilters { Returns if it matches any of the values */ pub loader_fields: Option, + #[serde(default = "default_true")] + pub include_changelog: bool, } pub async fn version_list( @@ -856,10 +870,16 @@ pub async fn version_list( }); response.dedup_by(|a, b| a.inner.id == b.inner.id); - let response = + let mut response = filter_visible_versions(response, &user_option, &pool, &redis) .await?; + if !filters.include_changelog { + for version in &mut response { + version.changelog = None; + } + } + Ok(HttpResponse::Ok().json(response)) } else { Err(ApiError::NotFound) diff --git a/apps/labrinth/tests/v2/version.rs b/apps/labrinth/tests/v2/version.rs index d7ba899f..afa47e97 100644 --- a/apps/labrinth/tests/v2/version.rs +++ b/apps/labrinth/tests/v2/version.rs @@ -84,7 +84,7 @@ pub async fn test_patch_version() { .await; assert_eq!(version.name, "new version name"); assert_eq!(version.version_number, "1.3.0"); - assert_eq!(version.changelog, "new changelog"); + assert_eq!(version.changelog, Some("new changelog".into())); assert_eq!( version.version_type, serde_json::from_str::("\"beta\"").unwrap() diff --git a/packages/muralpay/src/account.rs b/packages/muralpay/src/account.rs index 7a124b90..959c1c05 100644 --- a/packages/muralpay/src/account.rs +++ b/packages/muralpay/src/account.rs @@ -13,7 +13,9 @@ const _: () = { use crate::{MuralError, RequestExt}; impl crate::Client { - pub async fn get_all_accounts(&self) -> Result, MuralError> { + pub async fn get_all_accounts( + &self, + ) -> Result, MuralError> { maybe_mock!(self, get_all_accounts()); self.http_get(|base| format!("{base}/api/accounts")) @@ -21,7 +23,10 @@ const _: () = { .await } - pub async fn get_account(&self, id: AccountId) -> Result { + pub async fn get_account( + &self, + id: AccountId, + ) -> Result { maybe_mock!(self, get_account(id)); self.http_get(|base| format!("{base}/api/accounts/{id}")) @@ -43,7 +48,10 @@ const _: () = { maybe_mock!( self, - create_account(name.as_ref(), description.as_ref().map(AsRef::as_ref)) + create_account( + name.as_ref(), + description.as_ref().map(AsRef::as_ref) + ) ); let body = Body { @@ -59,7 +67,18 @@ const _: () = { } }; -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Deref, Serialize, Deserialize)] +#[derive( + Debug, + Display, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Deref, + Serialize, + Deserialize, +)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[display("{}", _0.hyphenated())] pub struct AccountId(pub Uuid); diff --git a/packages/muralpay/src/client/error.rs b/packages/muralpay/src/client/error.rs index 507f7368..b71129b8 100644 --- a/packages/muralpay/src/client/error.rs +++ b/packages/muralpay/src/client/error.rs @@ -69,7 +69,8 @@ impl fmt::Display for ApiError { if !self.params.is_empty() { lines.push("params:".into()); - lines.extend(self.params.iter().map(|(k, v)| format!("- {k}: {v}"))); + lines + .extend(self.params.iter().map(|(k, v)| format!("- {k}: {v}"))); } lines.push(format!("error name: {}", self.name)); diff --git a/packages/muralpay/src/client/mock.rs b/packages/muralpay/src/client/mock.rs index c06e4231..91ebb185 100644 --- a/packages/muralpay/src/client/mock.rs +++ b/packages/muralpay/src/client/mock.rs @@ -2,10 +2,11 @@ use { crate::{ - Account, AccountId, BankDetailsResponse, Counterparty, CounterpartyId, CreateCounterparty, - CreatePayout, FiatAndRailCode, FiatFeeRequest, FiatPayoutFee, MuralError, Organization, - OrganizationId, PayoutMethod, PayoutMethodDetails, PayoutMethodId, PayoutRequest, - PayoutRequestId, PayoutStatusFilter, SearchParams, SearchRequest, SearchResponse, + Account, AccountId, BankDetailsResponse, Counterparty, CounterpartyId, + CreateCounterparty, CreatePayout, FiatAndRailCode, FiatFeeRequest, + FiatPayoutFee, MuralError, Organization, OrganizationId, PayoutMethod, + PayoutMethodDetails, PayoutMethodId, PayoutRequest, PayoutRequestId, + PayoutStatusFilter, SearchParams, SearchRequest, SearchResponse, TokenFeeRequest, TokenPayoutFee, UpdateCounterparty, transaction::{Transaction, TransactionId}, }, diff --git a/packages/muralpay/src/client/mod.rs b/packages/muralpay/src/client/mod.rs index 2af18855..ec8bebdd 100644 --- a/packages/muralpay/src/client/mod.rs +++ b/packages/muralpay/src/client/mod.rs @@ -46,26 +46,40 @@ impl Client { api_url: String::new(), api_key: SecretString::from(String::new()), transfer_api_key: SecretString::from(String::new()), - mock: std::sync::Arc::new(arc_swap::ArcSwapOption::from_pointee(mock)), + mock: std::sync::Arc::new(arc_swap::ArcSwapOption::from_pointee( + mock, + )), } } - fn http_req(&self, make_req: impl FnOnce() -> RequestBuilder) -> RequestBuilder { + fn http_req( + &self, + make_req: impl FnOnce() -> RequestBuilder, + ) -> RequestBuilder { make_req() .bearer_auth(self.api_key.expose_secret()) .header("accept", "application/json") .header("content-type", "application/json") } - pub(crate) fn http_get(&self, make_url: impl FnOnce(&str) -> U) -> RequestBuilder { + pub(crate) fn http_get( + &self, + make_url: impl FnOnce(&str) -> U, + ) -> RequestBuilder { self.http_req(|| self.http.get(make_url(&self.api_url))) } - pub(crate) fn http_post(&self, make_url: impl FnOnce(&str) -> U) -> RequestBuilder { + pub(crate) fn http_post( + &self, + make_url: impl FnOnce(&str) -> U, + ) -> RequestBuilder { self.http_req(|| self.http.post(make_url(&self.api_url))) } - pub(crate) fn http_put(&self, make_url: impl FnOnce(&str) -> U) -> RequestBuilder { + pub(crate) fn http_put( + &self, + make_url: impl FnOnce(&str) -> U, + ) -> RequestBuilder { self.http_req(|| self.http.put(make_url(&self.api_url))) } diff --git a/packages/muralpay/src/counterparty.rs b/packages/muralpay/src/counterparty.rs index a7fae8ac..bb61f702 100644 --- a/packages/muralpay/src/counterparty.rs +++ b/packages/muralpay/src/counterparty.rs @@ -15,7 +15,8 @@ const _: () = { pub async fn search_counterparties( &self, params: Option>, - ) -> Result, MuralError> { + ) -> Result, MuralError> + { maybe_mock!(self, search_counterparties(params)); self.http_post(|base| format!("{base}/api/counterparties/search")) @@ -30,9 +31,11 @@ const _: () = { ) -> Result { maybe_mock!(self, get_counterparty(id)); - self.http_get(|base| format!("{base}/api/counterparties/counterparty/{id}")) - .send_mural() - .await + self.http_get(|base| { + format!("{base}/api/counterparties/counterparty/{id}") + }) + .send_mural() + .await } pub async fn create_counterparty( @@ -70,15 +73,28 @@ const _: () = { let body = Body { counterparty }; - self.http_put(|base| format!("{base}/api/counterparties/counterparty/{id}")) - .json(&body) - .send_mural() - .await + self.http_put(|base| { + format!("{base}/api/counterparties/counterparty/{id}") + }) + .json(&body) + .send_mural() + .await } } }; -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Deref, Serialize, Deserialize)] +#[derive( + Debug, + Display, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Deref, + Serialize, + Deserialize, +)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[display("{}", _0.hyphenated())] pub struct CounterpartyId(pub Uuid); diff --git a/packages/muralpay/src/organization.rs b/packages/muralpay/src/organization.rs index 71053e8f..10edc14f 100644 --- a/packages/muralpay/src/organization.rs +++ b/packages/muralpay/src/organization.rs @@ -15,7 +15,8 @@ const _: () = { pub async fn search_organizations( &self, req: SearchRequest, - ) -> Result, MuralError> { + ) -> Result, MuralError> + { #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] struct Body { @@ -41,8 +42,9 @@ const _: () = { let query = [ req.limit.map(|limit| ("limit", limit.to_string())), - req.next_id - .map(|next_id| ("nextId", next_id.hyphenated().to_string())), + req.next_id.map(|next_id| { + ("nextId", next_id.hyphenated().to_string()) + }), ] .into_iter() .flatten() @@ -75,7 +77,18 @@ const _: () = { } }; -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Deref, Serialize, Deserialize)] +#[derive( + Debug, + Display, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Deref, + Serialize, + Deserialize, +)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[display("{}", _0.hyphenated())] pub struct OrganizationId(pub Uuid); diff --git a/packages/muralpay/src/payout_method.rs b/packages/muralpay/src/payout_method.rs index cde19071..bf98fb10 100644 --- a/packages/muralpay/src/payout_method.rs +++ b/packages/muralpay/src/payout_method.rs @@ -1,8 +1,8 @@ use { crate::{ - ArsSymbol, BobSymbol, BrlSymbol, ClpSymbol, CopSymbol, CounterpartyId, CrcSymbol, - DocumentType, EurSymbol, FiatAccountType, MxnSymbol, PenSymbol, UsdSymbol, WalletDetails, - ZarSymbol, + ArsSymbol, BobSymbol, BrlSymbol, ClpSymbol, CopSymbol, CounterpartyId, + CrcSymbol, DocumentType, EurSymbol, FiatAccountType, MxnSymbol, + PenSymbol, UsdSymbol, WalletDetails, ZarSymbol, }, chrono::{DateTime, Utc}, derive_more::{Deref, Display, Error}, @@ -21,7 +21,8 @@ const _: () = { &self, counterparty_id: CounterpartyId, params: Option>, - ) -> Result, MuralError> { + ) -> Result, MuralError> + { maybe_mock!(self, search_payout_methods(counterparty_id, params)); self.http_post(|base| { @@ -37,7 +38,10 @@ const _: () = { counterparty_id: CounterpartyId, payout_method_id: PayoutMethodId, ) -> Result { - maybe_mock!(self, get_payout_method(counterparty_id, payout_method_id)); + maybe_mock!( + self, + get_payout_method(counterparty_id, payout_method_id) + ); self.http_get(|base| { format!( @@ -63,7 +67,11 @@ const _: () = { maybe_mock!( self, - create_payout_method(counterparty_id, alias.as_ref(), payout_method) + create_payout_method( + counterparty_id, + alias.as_ref(), + payout_method + ) ); let body = Body { @@ -72,7 +80,9 @@ const _: () = { }; self.http_post(|base| { - format!("{base}/api/counterparties/{counterparty_id}/payout-methods") + format!( + "{base}/api/counterparties/{counterparty_id}/payout-methods" + ) }) .json(&body) .send_mural() @@ -121,7 +131,18 @@ pub enum PayoutMethodPixAccountType { BankAccount, } -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Deref, Serialize, Deserialize)] +#[derive( + Debug, + Display, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Deref, + Serialize, + Deserialize, +)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[display("{}", _0.hyphenated())] pub struct PayoutMethodId(pub Uuid); diff --git a/packages/muralpay/src/serde_iso3166.rs b/packages/muralpay/src/serde_iso3166.rs index 8769107c..20979283 100644 --- a/packages/muralpay/src/serde_iso3166.rs +++ b/packages/muralpay/src/serde_iso3166.rs @@ -4,7 +4,10 @@ use { std::borrow::Cow, }; -pub fn serialize(v: &CountryCode, serializer: S) -> Result { +pub fn serialize( + v: &CountryCode, + serializer: S, +) -> Result { serializer.serialize_str(v.alpha2) } @@ -15,6 +18,8 @@ pub fn deserialize<'de, D: serde::Deserializer<'de>>( rust_iso3166::ALPHA2_MAP .get(&country_code) .copied() - .ok_or_else(|| D::Error::custom("invalid ISO 3166 alpha-2 country code")) + .ok_or_else(|| { + D::Error::custom("invalid ISO 3166 alpha-2 country code") + }) }) } diff --git a/packages/muralpay/src/transaction.rs b/packages/muralpay/src/transaction.rs index 088f8dd2..c299750c 100644 --- a/packages/muralpay/src/transaction.rs +++ b/packages/muralpay/src/transaction.rs @@ -5,14 +5,21 @@ use derive_more::{Deref, Display}; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{AccountId, Blockchain, FiatAmount, PayoutId, PayoutRequestId, TokenAmount}; +use crate::{ + AccountId, Blockchain, FiatAmount, PayoutId, PayoutRequestId, TokenAmount, +}; #[cfg(feature = "client")] const _: () = { - use crate::{Account, MuralError, RequestExt, SearchParams, SearchResponse}; + use crate::{ + Account, MuralError, RequestExt, SearchParams, SearchResponse, + }; impl crate::Client { - pub async fn get_transaction(&self, id: TransactionId) -> Result { + pub async fn get_transaction( + &self, + id: TransactionId, + ) -> Result { maybe_mock!(self, get_transaction(id)); self.http_get(|base| format!("{base}/api/transactions/{id}")) @@ -27,15 +34,28 @@ const _: () = { ) -> Result, MuralError> { maybe_mock!(self, search_transactions(account_id, params)); - self.http_post(|base| format!("{base}/api/transactions/search/account/{account_id}")) - .query(¶ms.map(|p| p.to_query()).unwrap_or_default()) - .send_mural() - .await + self.http_post(|base| { + format!("{base}/api/transactions/search/account/{account_id}") + }) + .query(¶ms.map(|p| p.to_query()).unwrap_or_default()) + .send_mural() + .await } } }; -#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, Hash, Deref, Serialize, Deserialize)] +#[derive( + Debug, + Display, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Deref, + Serialize, + Deserialize, +)] #[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))] #[display("{}", _0.hyphenated())] pub struct TransactionId(pub Uuid); diff --git a/packages/muralpay/src/util.rs b/packages/muralpay/src/util.rs index 70aae6c6..a3374eae 100644 --- a/packages/muralpay/src/util.rs +++ b/packages/muralpay/src/util.rs @@ -5,7 +5,8 @@ macro_rules! display_as_serialize { impl fmt::Display for $T { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = serde_json::to_value(self).map_err(|_| fmt::Error)?; + let value = + serde_json::to_value(self).map_err(|_| fmt::Error)?; let value = value.as_str().ok_or(fmt::Error)?; write!(f, "{value}") }