Git · dadoum.zone
Repositories
Help
Report an Issue
apple-crates
Code
Commits
Branches
Tags
Search
Tree:
a74924e
Branches
Tags
main
apple-crates
xcode
src
v1
bundle_ids.rs
Refactor and unify a lot of things for another project and implement airdrop support
Dadoum
commited
a74924e
at 2026-10-25 22:15:58
bundle_ids.rs
Blame
History
Raw
use super::{ BundleIDCapability, Page, PagedDocumentLinks, Relationship, ResourceIdentifier, comma_separated, }; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BundleIDPlatform { #[serde(rename = "IOS")] IOS, #[serde(rename = "MAC_OS")] MacOS, #[serde(rename = "UNIVERSAL")] Universal, #[serde(untagged)] Other(String), } #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BundleIDAttributes { pub name: String, pub platform: BundleIDPlatform, pub identifier: String, pub seed_id: Option<String>, } #[derive(Debug, Default, Deserialize)] #[serde(rename_all = "camelCase")] pub struct BundleIDRelationships { #[serde(default)] pub bundle_id_capabilities: Relationship<Vec<ResourceIdentifier>>, #[serde(default)] pub profiles: Relationship<Vec<ResourceIdentifier>>, } #[derive(Debug, Deserialize)] pub struct BundleID { pub id: String, pub attributes: BundleIDAttributes, #[serde(default)] pub relationships: BundleIDRelationships, } #[derive(Debug, Deserialize)] #[serde(tag = "type")] pub enum BundleIDIncluded { #[serde(rename = "bundleIdCapabilities")] BundleIDCapability(BundleIDCapability), #[serde(other)] Other, } #[derive(Debug, Deserialize)] pub struct BundleIDsResponse { pub data: Vec<BundleID>, #[serde(default)] pub included: Vec<BundleIDIncluded>, pub links: PagedDocumentLinks, } #[derive(Debug, Deserialize)] pub struct BundleIDResponse { pub data: BundleID, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub enum BundleIDInclude { #[serde(rename = "bundleIdCapabilities")] BundleIDCapabilities, } #[derive(Debug, Default, Serialize)] pub struct ListBundleIDsRequest { /// Matches identifiers by prefix. #[serde( rename = "filter[identifier]", serialize_with = "comma_separated", skip_serializing_if = "Vec::is_empty" )] pub filter_identifier: Vec<String>, #[serde( rename = "filter[platform]", serialize_with = "comma_separated", skip_serializing_if = "Vec::is_empty" )] pub filter_platform: Vec<BundleIDPlatform>, #[serde( serialize_with = "comma_separated", skip_serializing_if = "Vec::is_empty" )] pub include: Vec<BundleIDInclude>, #[serde( rename = "limit[bundleIdCapabilities]", skip_serializing_if = "Option::is_none" )] pub limit_bundle_id_capabilities: Option<u32>, #[serde(flatten)] pub page: Page, } impl_developer_api_request!(ListBundleIDsRequest, GET, "bundleIds", BundleIDsResponse); #[derive(Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct BundleIDCreateAttributes { pub name: String, pub platform: BundleIDPlatform, pub identifier: String, #[serde(skip_serializing_if = "Option::is_none")] pub seed_id: Option<String>, } #[derive(Debug, Serialize)] #[serde(tag = "type", rename = "bundleIds")] pub struct CreateBundleIDRequest { pub attributes: BundleIDCreateAttributes, } impl_developer_api_request!(CreateBundleIDRequest, POST, "bundleIds", BundleIDResponse); #[cfg(test)] mod tests { use super::*; use crate::v1::{CapabilityType, ResourceType}; #[test] fn bundle_ids_with_capabilities() { let response: BundleIDsResponse = serde_json::from_str( r#"{ "data": [{ "type": "bundleIds", "id": "8T4D9KSP2Q", "attributes": { "name": "Example", "platform": "IOS", "identifier": "com.example.app", "seedId": "ABCDE12345" }, "relationships": { "bundleIdCapabilities": { "meta": { "paging": { "total": 2, "limit": 10 } }, "data": [ { "type": "bundleIdCapabilities", "id": "8T4D9KSP2Q_GAME_CENTER" }, { "type": "bundleIdCapabilities", "id": "8T4D9KSP2Q_APP_GROUPS" } ], "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/relationships/bundleIdCapabilities", "related": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/bundleIdCapabilities" } }, "profiles": { "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/relationships/profiles", "related": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/profiles" } }, "app": { "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/relationships/app", "related": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q/app" } } }, "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q" } }, { "type": "bundleIds", "id": "W9JZ6K2L4M", "attributes": { "name": "XC Wildcard", "platform": "UNIVERSAL", "identifier": "*", "seedId": null } }], "included": [{ "type": "bundleIdCapabilities", "id": "8T4D9KSP2Q_GAME_CENTER", "attributes": { "capabilityType": "GAME_CENTER", "settings": null }, "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIdCapabilities/8T4D9KSP2Q_GAME_CENTER" } }, { "type": "profiles", "id": "2V7N3YH8QC", "attributes": { "name": "Example Development" } }], "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds?include=bundleIdCapabilities", "next": "https://api.appstoreconnect.apple.com/v1/bundleIds?cursor=Mg.ANi1Ck4&limit=2&include=bundleIdCapabilities" }, "meta": { "paging": { "total": 3, "limit": 2 } } }"#, ) .unwrap(); let bundle_id = &response.data[0]; assert_eq!(bundle_id.attributes.identifier, "com.example.app"); assert_eq!(bundle_id.attributes.platform, BundleIDPlatform::IOS); assert_eq!( bundle_id.relationships.bundle_id_capabilities.data[1], ResourceIdentifier { kind: ResourceType::BundleIDCapabilities, id: String::from("8T4D9KSP2Q_APP_GROUPS"), } ); assert!(bundle_id.relationships.profiles.data.is_empty()); assert_eq!( response.data[1].attributes.platform, BundleIDPlatform::Universal ); assert_eq!(response.data[1].attributes.seed_id, None); match &response.included[0] { BundleIDIncluded::BundleIDCapability(capability) => { assert_eq!( capability.attributes.capability_type, Some(CapabilityType::GameCenter) ); assert!(capability.attributes.settings.is_empty()); } BundleIDIncluded::Other => panic!("The capability should be modelled."), } assert!(matches!(response.included[1], BundleIDIncluded::Other)); assert_eq!(response.links.next_page().unwrap().limit, Some(2)); } #[test] fn create_bundle_id() { let request = CreateBundleIDRequest { attributes: BundleIDCreateAttributes { name: String::from("Example"), platform: BundleIDPlatform::IOS, identifier: String::from("com.example.app"), seed_id: None, }, }; assert_eq!( serde_json::to_value(&request).unwrap(), serde_json::json!({ "type": "bundleIds", "attributes": { "name": "Example", "platform": "IOS", "identifier": "com.example.app" } }) ); let request = ListBundleIDsRequest { filter_identifier: vec![String::from("com.example.app")], include: vec![BundleIDInclude::BundleIDCapabilities], ..Default::default() }; assert_eq!( serde_urlencoded::to_string(&request).unwrap(), "filter%5Bidentifier%5D=com.example.app&include=bundleIdCapabilities" ); let response: BundleIDResponse = serde_json::from_str( r#"{ "data": { "type": "bundleIds", "id": "8T4D9KSP2Q", "attributes": { "name": "Example", "platform": "IOS", "identifier": "com.example.app", "seedId": "ABCDE12345" }, "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds/8T4D9KSP2Q" } }, "links": { "self": "https://api.appstoreconnect.apple.com/v1/bundleIds" } }"#, ) .unwrap(); assert_eq!(response.data.id, "8T4D9KSP2Q"); assert_eq!( response.data.attributes.seed_id.as_deref(), Some("ABCDE12345") ); } }