diff --git a/http/Cargo.toml b/http/Cargo.toml index 99bd2dd..08ffb72 100644 --- a/http/Cargo.toml +++ b/http/Cargo.toml @@ -55,6 +55,9 @@ features = ["http1", "native-tokio", "logging", "tls12"] version = "2.0.5" path = "../model" +[dev-dependencies] +uuid = "1.21" + [features] blocking = [] redis = ["dep:redis"] diff --git a/http/src/client/requester.rs b/http/src/client/requester.rs index db6f57a..c242fa4 100644 --- a/http/src/client/requester.rs +++ b/http/src/client/requester.rs @@ -136,10 +136,11 @@ pub trait Requester: Sized + Sync } }; + let formated_id = T::format_id(&id); let request = build_request::( self, - T::format_url(T::format_id(&id).as_ref()), - None, + T::format_url(&formated_id), + T::extra_queries(&formated_id), )?; let response = exec_req::(self, request).await?; diff --git a/http/tests/guild.rs b/http/tests/guild.rs new file mode 100644 index 0000000..605fa4b --- /dev/null +++ b/http/tests/guild.rs @@ -0,0 +1,55 @@ +#![cfg(feature = "blocking")] + +use gw2lib::Requester; +use gw2lib_model::guild::{ + emblem::{GuildEmblemBackground, GuildEmblemForeground}, + permissions::GuildPermission, + search::GuildSearch, + upgrades::GuildUpgrade, + Guild, +}; +use uuid::uuid; + +pub mod setup; + +#[test] +fn by_id() { + let client = setup::setup(); + let gid = uuid!("4BBB52AA-D768-4FC6-8EDE-C299F2822F0F"); + let g: Guild = client.single(gid).unwrap(); + assert_eq!(g.id, gid); +} + +#[test] +fn emblem_backgrounds() { + let client = setup::setup(); + let _: Vec = client.all().unwrap(); +} + +#[test] +fn emblem_foregrounds() { + let client = setup::setup(); + let _: Vec = client.all().unwrap(); +} + +#[test] +fn permissions() { + let client = setup::setup(); + let _: Vec = client.all().unwrap(); +} + +#[test] +fn search() { + let client = setup::setup(); + let ids: GuildSearch = client.single("Arenanet".to_owned()).unwrap(); + assert_eq!( + ids.0.first().unwrap(), + &uuid!("4BBB52AA-D768-4FC6-8EDE-C299F2822F0F") + ) +} + +#[test] +fn upgrades() { + let client = setup::setup(); + let _: Vec = client.all().unwrap(); +} diff --git a/model/Cargo.toml b/model/Cargo.toml index 2f88513..b549cdb 100644 --- a/model/Cargo.toml +++ b/model/Cargo.toml @@ -17,6 +17,10 @@ path = "src/lib.rs" [dependencies] urlencoding = "2.1.2" +[dependencies.uuid] +version = "1.21" +features = ["serde"] + [dependencies.either] version = "1.8.1" features = ["serde"] diff --git a/model/README.md b/model/README.md index 99fca4d..47e7ea9 100644 --- a/model/README.md +++ b/model/README.md @@ -20,7 +20,7 @@ You don't even need to fork this library to test your struct! Example commit adding an endpoint: [bcb0bd3](https://github.com/greaka/gw2lib/commit/bcb0bd3e99f135f54fb01d088714ce8471a56d86) -> Last update: 2025/11/03 +> Last update: 2026/02/17 - achievements - [x] achievements @@ -107,11 +107,11 @@ Example commit adding an endpoint: [bcb0bd3](https://github.com/greaka/gw2lib/co - [ ] legends - guild - guild - - [ ] :id - - [ ] permissions - - [ ] search - - [ ] upgrades - - [ ] emblem + - [x] :id + - [x] permissions + - [x] search + - [x] upgrades + - [x] emblem - guild authenticated - guild - :id diff --git a/model/src/guild.rs b/model/src/guild.rs index 9460bc0..79cee90 100644 --- a/model/src/guild.rs +++ b/model/src/guild.rs @@ -1 +1,67 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::{ + guild::emblem::{GuildEmblemBackgroundId, GuildEmblemForegroundId}, + misc::colors::ColorId, + Endpoint, EndpointWithId, +}; + +pub mod emblem; +pub mod permissions; +pub mod search; pub mod upgrades; + +pub type GuildId = Uuid; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum GuildEmblemFlag { + FlipBackgroundHorizontal, + FlipBackgroundVertical, + FlipForegroundHorizontal, + FlipForegroundVertical, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildEmblemBackLayer { + pub id: GuildEmblemBackgroundId, + pub colors: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildEmblemForeLayer { + pub id: GuildEmblemForegroundId, + pub colors: Vec, +} + + + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildEmblem { + pub background: GuildEmblemBackLayer, + pub foreground: GuildEmblemForeLayer, + pub flags: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct Guild { + pub id: GuildId, + pub name: String, + pub tag: String, + pub emblem: Option, +} + +impl Endpoint for Guild { + const AUTHENTICATED: bool = false; + const LOCALE: bool = false; + const URL: &'static str = "v2/guild"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for Guild { + type IdType = GuildId; +} diff --git a/model/src/guild/emblem.rs b/model/src/guild/emblem.rs new file mode 100644 index 0000000..496019f --- /dev/null +++ b/model/src/guild/emblem.rs @@ -0,0 +1,58 @@ +use serde::{Deserialize, Serialize}; + +use crate::{BulkEndpoint, Endpoint, EndpointWithId}; + +pub type GuildEmblemBackgroundId = u32; +pub type GuildEmblemForegroundId = u32; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildEmblemBackground { + pub id: GuildEmblemBackgroundId, + pub layers: Vec, +} + +impl Endpoint for GuildEmblemBackground { + const AUTHENTICATED: bool = false; + const LOCALE: bool = false; + const URL: &'static str = "v2/emblem/backgrounds"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for GuildEmblemBackground { + type IdType = GuildEmblemBackgroundId; +} + +impl BulkEndpoint for GuildEmblemBackground { + const ALL: bool = true; + + fn id(&self) -> &Self::IdType { + &self.id + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildEmblemForeground { + pub id: GuildEmblemForegroundId, + pub layers: Vec, +} + +impl Endpoint for GuildEmblemForeground { + const AUTHENTICATED: bool = false; + const LOCALE: bool = false; + const URL: &'static str = "v2/emblem/foregrounds"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for GuildEmblemForeground { + type IdType = GuildEmblemForegroundId; +} + +impl BulkEndpoint for GuildEmblemForeground { + const ALL: bool = true; + + fn id(&self) -> &Self::IdType { + &self.id + } +} diff --git a/model/src/guild/permissions.rs b/model/src/guild/permissions.rs new file mode 100644 index 0000000..4f10988 --- /dev/null +++ b/model/src/guild/permissions.rs @@ -0,0 +1,32 @@ +use serde::{Deserialize, Serialize}; + +use crate::{BulkEndpoint, Endpoint, EndpointWithId}; + +pub type GuildPermissionId = String; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildPermission { + pub id: GuildPermissionId, + pub name: String, + pub description: String, +} + +impl Endpoint for GuildPermission { + const AUTHENTICATED: bool = false; + const LOCALE: bool = true; + const URL: &'static str = "v2/guild/permissions"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for GuildPermission { + type IdType = GuildPermissionId; +} + +impl BulkEndpoint for GuildPermission { + const ALL: bool = true; + + fn id(&self) -> &Self::IdType { + &self.id + } +} diff --git a/model/src/guild/search.rs b/model/src/guild/search.rs new file mode 100644 index 0000000..0887bf2 --- /dev/null +++ b/model/src/guild/search.rs @@ -0,0 +1,26 @@ +use serde::{Deserialize, Serialize}; + +use crate::{guild::GuildId, Endpoint, EndpointWithId}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(transparent)] +pub struct GuildSearch(pub Vec); + +impl Endpoint for GuildSearch { + const AUTHENTICATED: bool = false; + const LOCALE: bool = false; + const URL: &'static str = "v2/guild/search"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for GuildSearch { + type IdType = String; + + fn format_url(_id: &str) -> String { + Self::URL.to_string() + } + + fn extra_queries(id: &str) -> Option { + Some(format!("name={}", id)) + } +} diff --git a/model/src/guild/upgrades.rs b/model/src/guild/upgrades.rs index 862c386..46f8042 100644 --- a/model/src/guild/upgrades.rs +++ b/model/src/guild/upgrades.rs @@ -1 +1,76 @@ +use serde::{Deserialize, Serialize}; + +use crate::{items::ItemId, BulkEndpoint, Endpoint, EndpointWithId}; + pub type GuildUpgradeId = u64; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum GuildUpgradeType { + AccumulatingCurrency, + BankBag, + Boost, + Claimable, + Consumable, + Decoration, + GuildHall, + GuildHallExpedition, + Hub, + Queue, + Unlock, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum GuildUpgradeCostType { + Item, + Collectible, + Currency, + Coins, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildUpgradeCost { + #[serde(rename = "type")] + pub cost_type: GuildUpgradeCostType, + pub name: Option, + pub count: u32, + pub item_id: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[cfg_attr(test, serde(deny_unknown_fields))] +pub struct GuildUpgrade { + pub id: GuildUpgradeId, + pub name: String, + pub description: String, + #[serde(rename = "type")] + pub upgrade_type: GuildUpgradeType, + pub icon: String, + pub build_time: u32, + pub required_level: u32, + pub experience: u32, + pub prerequisites: Vec, + pub bag_max_items: Option, + pub bag_max_coins: Option, + #[serde(default)] + pub cost: Vec, +} + +impl Endpoint for GuildUpgrade { + const AUTHENTICATED: bool = false; + const LOCALE: bool = true; + const URL: &'static str = "v2/guild/upgrades"; + const VERSION: &'static str = "2026-02-17T00:00:00.000Z"; +} + +impl EndpointWithId for GuildUpgrade { + type IdType = GuildUpgradeId; +} + +impl BulkEndpoint for GuildUpgrade { + const ALL: bool = true; + + fn id(&self) -> &Self::IdType { + &self.id + } +} diff --git a/model/src/lib.rs b/model/src/lib.rs index 2241fd0..8c96b14 100644 --- a/model/src/lib.rs +++ b/model/src/lib.rs @@ -90,6 +90,11 @@ pub trait EndpointWithId: Endpoint { fn format_url(id: &str) -> String { format!("{}/{}", Self::URL, id) } + + #[expect(unused_variables)] + fn extra_queries(id: &str) -> Option { + None + } } pub trait FixedEndpoint: Endpoint {}