Skip to content

Commit 829b845

Browse files
committed
feat: get all contributors in all the organization's repositories
1 parent 8143baa commit 829b845

File tree

2 files changed

+134
-36
lines changed

2 files changed

+134
-36
lines changed

src/components/cards/contributor_card.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub fn ContributorCard(
1010
#[prop(into)] location: Option<String>,
1111
#[prop(into)] link: String,
1212
#[prop(into)] brand_src: String,
13-
#[prop(into)] contributions: i32,
13+
#[prop(into)] contributions: u64,
1414
) -> impl IntoView {
1515
view! {
1616
<article class="hover:z-10">

src/pages/contributors.rs

+133-35
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,92 @@
1-
use futures::future::join_all;
2-
use leptos::{create_local_resource, error::Result, island, view, Fragment, IntoView, SignalGet};
1+
#[cfg(not(debug_assertions))]
2+
use leptos::{create_local_resource, SignalGet};
3+
use leptos::{error::Result, island, serde_json::json, view, Fragment, IntoView};
34
use serde::{Deserialize, Serialize};
45

5-
use crate::{components::ContributorCard, error, log};
6+
use crate::components::ContributorCard;
7+
8+
#[cfg(not(debug_assertions))]
9+
const GRAPH_QUERY: &str = r#"
10+
query OrganizationContributors {
11+
organization(login: "RustLangES") {
12+
repositories(first: 100) {
13+
nodes {
14+
collaborators(first: 100) {
15+
nodes {
16+
login
17+
avatarUrl
18+
url
19+
bio
20+
twitterUsername
21+
location
22+
contributionsCollection {
23+
totalCommitContributions
24+
}
25+
}
26+
}
27+
}
28+
}
29+
}
30+
}
31+
"#;
632

733
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
834
pub struct Contributor {
935
login: String,
1036
avatar_url: String,
11-
html_url: String,
37+
url: String,
1238
bio: Option<String>,
1339
twitter_username: Option<String>,
1440
location: Option<String>,
15-
contributions: Option<i32>,
41+
contributions_collection: ContributionCollection,
42+
}
43+
44+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
45+
pub struct ContributionCollection {
46+
total_commit_contributions: u64,
1647
}
1748

49+
#[cfg(not(debug_assertions))]
1850
async fn fetch_contributors() -> Result<Vec<Contributor>> {
19-
let response = reqwasm::http::Request::get(
20-
"https://api.github.com/repos/RustLangES/rustlanges.github.io/contributors",
21-
)
22-
.send()
23-
.await?
24-
.json::<Vec<Contributor>>()
25-
.await?;
26-
27-
let response = join_all(response.iter().map(fetch_contributor_info))
28-
.await
51+
let request_body = json!({
52+
"query": GRAPH_QUERY,
53+
});
54+
55+
let mut headers = reqwest::header::HeaderMap::new();
56+
57+
headers.append(
58+
"Authorization",
59+
format!("Bearer {}", env!("GITHUB_API_TOKEN"))
60+
.parse()
61+
.unwrap(),
62+
);
63+
64+
let client = reqwest::ClientBuilder::new()
65+
.default_headers(headers)
66+
.build()?;
67+
68+
let res: leptos::serde_json::Value = client
69+
.post("https://api.github.com/graphql")
70+
.send()
71+
.await?
72+
.json()
73+
.await?;
74+
75+
let mut res = res["data"]["organization"]["repositories"]["nodes"]
76+
.as_array()
77+
.unwrap_or(&Vec::new())
2978
.iter()
30-
.flat_map(|c| c.clone().ok())
31-
.collect::<Vec<Contributor>>();
79+
.flat_map(|repo| repo["contributors"]["nodes"].as_array().unwrap())
80+
.map(|c| leptos::serde_json::from_value::<Contributor>(c.clone()).map_err(|e| e.into()))
81+
.collect::<Result<Vec<Contributor>>>()?;
3282

33-
Ok(response)
34-
}
83+
res.sort_by_key(|a| a.contributions_collection.total_commit_contributions);
3584

36-
async fn fetch_contributor_info(contributor: &Contributor) -> Result<Contributor> {
37-
Ok(reqwasm::http::Request::get(&format!(
38-
"https://api.github.com/users/{}",
39-
contributor.login
40-
))
41-
.send()
42-
.await?
43-
.json::<Contributor>()
44-
.await
45-
.inspect(|c| log!("{c:?} - {contributor:?}"))
46-
.inspect_err(|e| error!("Error: {e:?}"))
47-
.map(|c| Contributor {
48-
contributions: contributor.contributions,
49-
..c
50-
})?)
85+
Ok(res)
5186
}
5287

53-
#[island]
88+
#[cfg_attr(not(debug_assertions), island)]
89+
#[cfg(not(debug_assertions))]
5490
pub fn Contributors() -> impl IntoView {
5591
let contributors_results = create_local_resource(move || (), |()| fetch_contributors());
5692
let contributorMapper = |item: &Contributor| {
@@ -90,3 +126,65 @@ pub fn Contributors() -> impl IntoView {
90126
</section>
91127
}
92128
}
129+
130+
#[cfg_attr(debug_assertions, island)]
131+
#[cfg(debug_assertions)]
132+
pub fn Contributors() -> impl IntoView {
133+
let contributors = [Contributor {
134+
login: "Phosphorus-M".to_owned(),
135+
avatar_url: "https://avatars.githubusercontent.com/u/19656993?v=4".to_owned(),
136+
url: "https://github.com/Phosphorus-M".to_owned(),
137+
bio: None,
138+
twitter_username: Some("Phosphorus_M".to_owned()),
139+
location: Some("Argentina".to_owned()),
140+
contributions_collection: ContributionCollection {
141+
total_commit_contributions: 499,
142+
},
143+
},
144+
Contributor {
145+
login: "SergioRibera".to_owned(),
146+
avatar_url: "https://avatars.githubusercontent.com/u/56278796?u=9e3dac947b4fd3ca2f1a05024e083c64e4c69cfe&v=4".to_owned(),
147+
url: "https://github.com/SergioRibera".to_owned(),
148+
bio: Some("22yo Rustacean and Open Source lover\r\nI teach, Promote and Give Technical talks of rust with @RustLangES".to_owned()),
149+
twitter_username: Some("sergioribera_rs".to_owned()),
150+
location: Some("Santa Cruz de la Sierra, Bolivia".to_owned()),
151+
contributions_collection: ContributionCollection {
152+
total_commit_contributions: 2015
153+
}
154+
}];
155+
let contributorMapper = |item: &Contributor| {
156+
view! {
157+
<ContributorCard
158+
name=item.login.clone()
159+
description=item.bio.clone()
160+
link=item.url.clone()
161+
brand_src=item.avatar_url.clone()
162+
twitter=item.twitter_username.clone()
163+
location=item.location.clone()
164+
contributions=item.contributions_collection.total_commit_contributions
165+
/>
166+
}
167+
};
168+
169+
let contributors_view = move || {
170+
let result = contributors
171+
.iter()
172+
.map(contributorMapper)
173+
.collect::<Fragment>();
174+
Some(result.into_view())
175+
};
176+
177+
view! {
178+
<section class="bg-orange-300/30 dark:bg-transparent py-16">
179+
<div class="flex flex-col gap-y-6 container mx-auto px-4">
180+
<h2 class="text-3xl text-left mb-6">
181+
<span class="font-work-sans font-light">"Nuestros "</span>
182+
<span class="font-alfa-slab text-orange-500">"Colaboradores"</span>
183+
</h2>
184+
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-5 gap-6">
185+
{contributors_view}
186+
</div>
187+
</div>
188+
</section>
189+
}
190+
}

0 commit comments

Comments
 (0)