@@ -2,8 +2,8 @@ use chrono::{DateTime, Utc};
22
33use crate :: external_urls:: remove_blocked_urls;
44use crate :: models:: {
5- ApiToken , Category , Crate , Dependency , DependencyKind , Keyword , Owner , ReverseDependency , Team ,
6- TopVersions , User , Version , VersionDownload , VersionOwnerAction ,
5+ ApiToken , Category , Crate , Dependency , DependencyKind , Keyword , LinkedAccount , Owner ,
6+ ReverseDependency , Team , TopVersions , User , Version , VersionDownload , VersionOwnerAction ,
77} ;
88use crates_io_github as github;
99
@@ -790,9 +790,15 @@ pub struct EncodablePublicUser {
790790 /// The user's GitHub profile URL.
791791 #[ schema( example = "https://github.com/ghost" ) ]
792792 pub url : String ,
793+
794+ /// The accounts linked to this crates.io account.
795+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
796+ #[ schema( no_recursion, example = json!( [ ] ) ) ]
797+ pub linked_accounts : Option < Vec < EncodableLinkedAccount > > ,
793798}
794799
795- /// Converts a `User` model into an `EncodablePublicUser` for JSON serialization.
800+ /// Converts a `User` model into an `EncodablePublicUser` for JSON serialization. Does not include
801+ /// linked accounts.
796802impl From < User > for EncodablePublicUser {
797803 fn from ( user : User ) -> Self {
798804 let User {
@@ -805,13 +811,87 @@ impl From<User> for EncodablePublicUser {
805811 } = user;
806812 let url = format ! ( "https://github.com/{gh_login}" ) ;
807813 let username = username. unwrap_or ( gh_login) ;
814+
815+ EncodablePublicUser {
816+ id,
817+ login : username. clone ( ) ,
818+ username,
819+ name,
820+ avatar : gh_avatar,
821+ url,
822+ linked_accounts : None ,
823+ }
824+ }
825+ }
826+
827+ impl EncodablePublicUser {
828+ pub fn with_linked_accounts ( user : User , linked_accounts : & [ LinkedAccount ] ) -> Self {
829+ let User {
830+ id,
831+ name,
832+ username,
833+ gh_login,
834+ gh_avatar,
835+ ..
836+ } = user;
837+ let url = format ! ( "https://github.com/{gh_login}" ) ;
838+ let username = username. unwrap_or ( gh_login) ;
839+
840+ let linked_accounts = if linked_accounts. is_empty ( ) {
841+ None
842+ } else {
843+ Some ( linked_accounts. iter ( ) . map ( Into :: into) . collect ( ) )
844+ } ;
845+
808846 EncodablePublicUser {
809847 id,
810848 login : username. clone ( ) ,
811849 username,
812850 name,
813851 avatar : gh_avatar,
814852 url,
853+ linked_accounts,
854+ }
855+ }
856+ }
857+
858+ #[ derive( Deserialize , Serialize , Debug , PartialEq , Eq , utoipa:: ToSchema ) ]
859+ #[ schema( as = LinkedAccount ) ]
860+ pub struct EncodableLinkedAccount {
861+ /// The service providing this linked account.
862+ #[ schema( example = "GitHub" ) ]
863+ pub provider : String ,
864+
865+ /// The linked account's login name.
866+ #[ schema( example = "ghost" ) ]
867+ pub login : String ,
868+
869+ /// The linked account's avatar URL, if set.
870+ #[ schema( example = "https://avatars2.githubusercontent.com/u/1234567?v=4" ) ]
871+ pub avatar : Option < String > ,
872+
873+ /// The linked account's profile URL on the provided service.
874+ #[ schema( example = "https://github.com/ghost" ) ]
875+ pub url : String ,
876+ }
877+
878+ /// Converts a `LinkedAccount` model into an `EncodableLinkedAccount` for JSON serialization.
879+ impl From < & LinkedAccount > for EncodableLinkedAccount {
880+ fn from ( linked_account : & LinkedAccount ) -> Self {
881+ let LinkedAccount {
882+ provider,
883+ login,
884+ avatar,
885+ ..
886+ } = linked_account;
887+
888+ let url = provider. url ( login) ;
889+
890+ Self {
891+ provider : provider. to_string ( ) ,
892+ login : login. clone ( ) ,
893+ avatar : avatar. clone ( ) ,
894+ url,
815895 }
816896 }
817897}
@@ -1140,6 +1220,7 @@ mod tests {
11401220 name: None ,
11411221 avatar: None ,
11421222 url: String :: new( ) ,
1223+ linked_accounts: None ,
11431224 } ,
11441225 time: NaiveDate :: from_ymd_opt( 2017 , 1 , 6 )
11451226 . unwrap( )
0 commit comments