@@ -2,8 +2,8 @@ use chrono::{DateTime, Utc};
2
2
3
3
use crate :: external_urls:: remove_blocked_urls;
4
4
use 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 ,
7
7
} ;
8
8
use crates_io_github as github;
9
9
@@ -790,9 +790,15 @@ pub struct EncodablePublicUser {
790
790
/// The user's GitHub profile URL.
791
791
#[ schema( example = "https://github.com/ghost" ) ]
792
792
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 > > ,
793
798
}
794
799
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.
796
802
impl From < User > for EncodablePublicUser {
797
803
fn from ( user : User ) -> Self {
798
804
let User {
@@ -805,13 +811,87 @@ impl From<User> for EncodablePublicUser {
805
811
} = user;
806
812
let url = format ! ( "https://github.com/{gh_login}" ) ;
807
813
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
+
808
846
EncodablePublicUser {
809
847
id,
810
848
login : username. clone ( ) ,
811
849
username,
812
850
name,
813
851
avatar : gh_avatar,
814
852
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,
815
895
}
816
896
}
817
897
}
@@ -1140,6 +1220,7 @@ mod tests {
1140
1220
name: None ,
1141
1221
avatar: None ,
1142
1222
url: String :: new( ) ,
1223
+ linked_accounts: None ,
1143
1224
} ,
1144
1225
time: NaiveDate :: from_ymd_opt( 2017 , 1 , 6 )
1145
1226
. unwrap( )
0 commit comments