diff --git a/.changeset/sweet-otters-profile.md b/.changeset/sweet-otters-profile.md new file mode 100644 index 0000000..7718271 --- /dev/null +++ b/.changeset/sweet-otters-profile.md @@ -0,0 +1,7 @@ +--- +"@germ-network/atprotoclient": minor +--- + +Add `GetProfiles` request and associated data to profile defs + +Thanks @anna (anna@germ.network)! diff --git a/Sources/AtprotoClient/Agent/Agents/AuthPDSAgent.swift b/Sources/AtprotoClient/Agent/Agents/AuthPDSAgent.swift index a422aa2..b0bc853 100644 --- a/Sources/AtprotoClient/Agent/Agents/AuthPDSAgent.swift +++ b/Sources/AtprotoClient/Agent/Agents/AuthPDSAgent.swift @@ -7,7 +7,9 @@ import AtprotoTypes -public protocol AuthPDSAgent: Atproto.PDSAgent, Atproto.XRPC.ProxyCallable, Atproto.XRPC +extension Atproto { + public protocol AuthPDSAgent: Atproto.PDSAgent, Atproto.XRPC.ProxyCallable, Atproto.XRPC .AuthCallable -{ + { + } } diff --git a/Sources/AtprotoClient/Agent/Agents/GetAuthedSocialGraph.swift b/Sources/AtprotoClient/Agent/Agents/GetAuthedSocialGraph.swift index 9f1ada0..14aefa8 100644 --- a/Sources/AtprotoClient/Agent/Agents/GetAuthedSocialGraph.swift +++ b/Sources/AtprotoClient/Agent/Agents/GetAuthedSocialGraph.swift @@ -13,7 +13,7 @@ public enum BskyAppViewAuthedSocialGraphs: Sendable { case knownFollowers } -extension AuthPDSAgent { +extension Atproto.AuthPDSAgent { public func streamSocialGraphs( for actor: LexiconString.AtIdentifier, socialGraphType: BskyAppViewAuthedSocialGraphs, diff --git a/Sources/AtprotoClient/Lexicon/AppBsky/Actor/ActorDefs.swift b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/ActorDefs.swift index 37e3e60..23abc36 100644 --- a/Sources/AtprotoClient/Lexicon/AppBsky/Actor/ActorDefs.swift +++ b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/ActorDefs.swift @@ -27,7 +27,7 @@ extension Lexicon.App.Bsky.Actor.Defs { public let description: String? public let avatar: URL? - //public let associated: ProfileAssociated? + public let associated: ProfileAssociated? public let indexedAt: LexiconString.Datetime? public let createdAt: LexiconString.Datetime? @@ -46,6 +46,7 @@ extension Lexicon.App.Bsky.Actor.Defs { pronouns: String?, description: String?, avatar: URL?, + associated: ProfileAssociated?, indexedAt: LexiconString.Datetime?, createdAt: LexiconString.Datetime?, viewer: ViewerState? @@ -56,6 +57,7 @@ extension Lexicon.App.Bsky.Actor.Defs { self.pronouns = pronouns self.description = description self.avatar = avatar + self.associated = associated self.indexedAt = indexedAt self.createdAt = createdAt self.viewer = viewer @@ -88,7 +90,7 @@ extension Lexicon.App.Bsky.Actor.Defs { public let postsCount: Int? - //public let associated: ProfileAssociated? + public let associated: ProfileAssociated? //public let joinedViaStarterPack: JoinedViaStarterPack? public let indexedAt: LexiconString.Datetime? @@ -114,6 +116,7 @@ extension Lexicon.App.Bsky.Actor.Defs { followersCount: Int?, followsCount: Int?, postsCount: Int?, + associated: ProfileAssociated?, indexedAt: LexiconString.Datetime?, createdAt: LexiconString.Datetime?, viewer: ViewerState? @@ -129,6 +132,7 @@ extension Lexicon.App.Bsky.Actor.Defs { self.followersCount = followersCount self.followsCount = followsCount self.postsCount = postsCount + self.associated = associated self.indexedAt = indexedAt self.createdAt = createdAt self.viewer = viewer @@ -190,4 +194,41 @@ extension Lexicon.App.Bsky.Actor.Defs { self.followedBy = followedBy } } + + /// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/actor/defs.json + public struct ProfileAssociated: Sendable, Codable { + public let lists: Int? + public let feedgens: Int? + public let starterPacks: Int? + public let labeler: Bool? + // public let chat: ProfileAssociatedChat? + // public let activitySubscription: ProfileAssociatedActivitySubscription? + public let germ: ProfileAssociatedGerm? + + public init( + lists: Int?, + feedgens: Int?, + starterPacks: Int?, + labeler: Bool?, + germ: ProfileAssociatedGerm? + ) { + self.lists = lists + self.feedgens = feedgens + self.starterPacks = starterPacks + self.labeler = labeler + self.germ = germ + } + } + + /// [github]: https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/actor/defs.json + public struct ProfileAssociatedGerm: Sendable, Codable { + public let messageMeUrl: URL + // possible values: [usersIFollow, everyone] + public let showButtonTo: String + + public init(messageMeUrl: URL, showButtonTo: String) { + self.messageMeUrl = messageMeUrl + self.showButtonTo = showButtonTo + } + } } diff --git a/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfile.swift b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfile.swift index 5e2fea3..daee0a2 100644 --- a/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfile.swift +++ b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfile.swift @@ -1,6 +1,6 @@ // -// BskyGetProfile.swift -// AtprotoTypes +// GetProfile.swift +// AtprotoClient // // Created by Mark @ Germ on 2/26/26. // diff --git a/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfiles.swift b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfiles.swift new file mode 100644 index 0000000..11b835f --- /dev/null +++ b/Sources/AtprotoClient/Lexicon/AppBsky/Actor/GetProfiles.swift @@ -0,0 +1,48 @@ +// +// GetProfiles.swift +// AtprotoClient +// +// Created by Anna Mistele on 6/4/26. +// + +import AtprotoTypes +import Foundation +import GermConvenience + +///https://docs.bsky.app/docs/api/app-bsky-actor-get-profile +///https://lexicon.garden/lexicon/did:plc:4v4y5r3lwsbtmsxhile2ljac/app.bsky.actor.getProfile/docs +extension Lexicon.App.Bsky.Actor { + public enum GetProfiles: Atproto.XRPC.Request { + public struct Id: Atproto.XRPC.EndpointId { + public static var nsid: Atproto.NSID { + .init(string: "app.bsky.actor.getProfiles") + } + + public init() {} + } + + public static var outputEncoding: HTTPContentType { + .json + } + + public struct Parameters: QueryParametrizable { + public let actor: LexiconString.AtIdentifier + + public init(actor: LexiconString.AtIdentifier) { + self.actor = actor + } + + public func asQueryItems() -> [URLQueryItem] { + [.init(name: "actor", value: actor.rawValue)] + } + } + + public struct Output: Sendable, Codable { + public let profiles: [Lexicon.App.Bsky.Actor.Defs.ProfileViewDetailed] + } + } +} + +extension Lexicon.App.Bsky.Actor.GetProfiles: Atproto.XRPC.ResponseParsing { + public static var badRequestErrors: Set { defaultErrors } +} diff --git a/Sources/AtprotoClientMocks/Lexicon/App/Bsky/ActorDefs.swift b/Sources/AtprotoClientMocks/Lexicon/App/Bsky/ActorDefs.swift index 86509ea..ae72052 100644 --- a/Sources/AtprotoClientMocks/Lexicon/App/Bsky/ActorDefs.swift +++ b/Sources/AtprotoClientMocks/Lexicon/App/Bsky/ActorDefs.swift @@ -25,6 +25,8 @@ extension Lexicon.App.Bsky.Actor.Defs.ProfileViewDetailed: Mockable { followersCount: 2, followsCount: 5, postsCount: 10, + // TODO: Test with nil associated Germ as well + associated: .mock(), indexedAt: .init(date: .now), createdAt: .init(date: .distantPast), viewer: .init( @@ -51,3 +53,24 @@ extension Lexicon.App.Bsky.Actor.Profile: Mockable { ) } } + +extension Lexicon.App.Bsky.Actor.Defs.ProfileAssociated: Mockable { + public static func mock() -> Lexicon.App.Bsky.Actor.Defs.ProfileAssociated { + .init( + lists: nil, + feedgens: nil, + starterPacks: nil, + labeler: nil, + germ: .mock() + ) + } +} + +extension Lexicon.App.Bsky.Actor.Defs.ProfileAssociatedGerm: Mockable { + public static func mock() -> Lexicon.App.Bsky.Actor.Defs.ProfileAssociatedGerm { + .init( + messageMeUrl: URL(string: "https://landing.ger.mx/newUser")!, + showButtonTo: "usersIFollow" + ) + } +} diff --git a/Sources/AtprotoClientMocks/MockPDS/MockPDS.swift b/Sources/AtprotoClientMocks/MockPDS/MockPDS.swift index 95e0bdc..41c2928 100644 --- a/Sources/AtprotoClientMocks/MockPDS/MockPDS.swift +++ b/Sources/AtprotoClientMocks/MockPDS/MockPDS.swift @@ -354,7 +354,7 @@ extension MockPDS.PublicAgent: Atproto.PDSAgent { } } -extension MockPDS.AuthAgent: Atproto.PDSAgent, Atproto.XRPC.AuthCallable { +extension MockPDS.AuthAgent: Atproto.AuthPDSAgent { public func response( _ requestComponents: XRPCRequestComponents ) async throws -> HTTPDataResponse { diff --git a/Tests/AtprotoClientTests/OnlineTests.swift b/Tests/AtprotoClientTests/OnlineTests.swift index f742731..5244946 100644 --- a/Tests/AtprotoClientTests/OnlineTests.swift +++ b/Tests/AtprotoClientTests/OnlineTests.swift @@ -11,7 +11,7 @@ import Foundation import Testing #if canImport(FoundationNetworking) -import FoundationNetworking + import FoundationNetworking #endif struct OnlineTests {