summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKornel <kornel@geekhood.net>2020-03-23 00:20:35 +0000
committerKornel <kornel@geekhood.net>2020-03-23 00:20:35 +0000
commit0d8c22c6d93cf77045515a6be2bc87ee562cbefc (patch)
tree01d70a03352baa319c3d3620a2ab79e5f2a24870
parent6545c8dff8bcb92e97a324ca5aa398982d8fbcc4 (diff)
Rustaceans info
-rw-r--r--.gitmodules3
m---------data/rustaceans0
-rw-r--r--front_end/src/author_page.rs38
-rw-r--r--front_end/templates/author.rs.html13
-rw-r--r--kitchen_sink/src/lib_kitchen_sink.rs32
5 files changed, 81 insertions, 5 deletions
diff --git a/.gitmodules b/.gitmodules
index 8d3714d..aa120a9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
[submodule "data/index"]
path = data/index
url = https://github.com/rust-lang/crates.io-index.git
+[submodule "data/rustaceans"]
+ path = data/rustaceans
+ url = https://github.com/nrc/rustaceans.org
diff --git a/data/rustaceans b/data/rustaceans
new file mode 160000
+Subproject 36b6be9d5cbfcaaed29e4531ecef9ec22bdcb59
diff --git a/front_end/src/author_page.rs b/front_end/src/author_page.rs
index 2f06bab..31c0a5d 100644
--- a/front_end/src/author_page.rs
+++ b/front_end/src/author_page.rs
@@ -10,6 +10,7 @@ use kitchen_sink::Org;
use kitchen_sink::OwnerKind;
use kitchen_sink::RichAuthor;
use kitchen_sink::RichCrateVersion;
+use kitchen_sink::Rustacean;
use kitchen_sink::User;
use kitchen_sink::UserType;
use render_readme::Renderer;
@@ -38,10 +39,14 @@ pub struct AuthorPage<'a> {
pub(crate) member_total: usize,
pub(crate) keywords: Vec<String>,
pub(crate) collab: Vec<User>,
+ pub(crate) rustacean: Option<Rustacean>,
}
impl<'a> AuthorPage<'a> {
pub async fn new(aut: &'a RichAuthor, kitchen_sink: &'a KitchenSink, markup: &'a Renderer) -> CResult<AuthorPage<'a>> {
+
+ let rustacean = kitchen_sink.rustacean_for_github_login(&aut.github.login);
+
let orgs = kitchen_sink.user_github_orgs(&aut.github.login).await?.unwrap_or_default();
let orgs = futures::stream::iter(orgs).filter_map(|org| async move {
kitchen_sink.github_org(&org.login).await
@@ -111,6 +116,7 @@ impl<'a> AuthorPage<'a> {
joined,
keywords,
collab,
+ rustacean,
})
}
@@ -133,9 +139,39 @@ impl<'a> AuthorPage<'a> {
.collect().await
}
+ pub fn name(&self) -> Option<&str> {
+ let gh_name = self.aut.name();
+ if !gh_name.is_empty() && gh_name != self.login() {
+ return Some(gh_name);
+ }
+ self.rustacean.as_ref().and_then(|r| r.name.as_deref())
+ }
+
+ pub fn twitter_link(&self) -> Option<(String, &str)> {
+ eprintln!("{:?}", self.rustacean);
+ self.rustacean.as_ref().and_then(|r| r.twitter.as_deref())
+ .map(|t| t.trim_start_matches('@'))
+ .filter(|t| !t.is_empty())
+ .map(|t| {
+ (format!("https://twitter.com/{}", t), t)
+ })
+ }
+
+ pub fn forum_link(&self) -> Option<(String, &str)> {
+ self.rustacean.as_ref().and_then(|r| r.discourse.as_deref())
+ .map(|t| t.trim_start_matches('@'))
+ .filter(|t| !t.is_empty())
+ .map(|t| {
+ (format!("https://users.rust-lang.org/u/{}", t), t)
+ })
+ }
+
/// `(url, label)`
pub fn homepage_link(&self) -> Option<(&str, Cow<'_, str>)> {
- if let Some(url) = self.aut.github.blog.as_deref() {
+ let url = self.aut.github.blog.as_deref()
+ .or_else(|| self.rustacean.as_ref().and_then(|r| r.website.as_deref()))
+ .or_else(|| self.rustacean.as_ref().and_then(|r| r.blog.as_deref()));
+ if let Some(url) = url {
if url.starts_with("https://") || url.starts_with("http://") {
let label = url_domain(url)
.map(|host| {
diff --git a/front_end/templates/author.rs.html b/front_end/templates/author.rs.html
index f84dca3..54ad323 100644
--- a/front_end/templates/author.rs.html
+++ b/front_end/templates/author.rs.html
@@ -34,8 +34,8 @@
@if p.orgs.iter().any(|o| o.login == "rust-lang") {<span class=labels><span title="Member of the rust-lang org">Rust team</span></span>}
@p.login()
</h2>
- @if !p.aut.name().is_empty() && p.aut.name() != p.login() {
- <p class=desc>@p.aut.name()</p>
+ @if let Some(n) = p.name() {
+ <p class=desc>@n</p>
}
<p>
Joined crates-io @HumanTime::from(p.joined).to_text_en(Accuracy::Rough, Tense::Past)@if let Some(d) = p.joined_github() {.
@@ -50,6 +50,12 @@
@if let Some((url, label)) = p.homepage_link() {
<li><a href="@url" rel="ugc nofollow" >@label</a></li>
}
+ @if let Some((url, label)) = p.twitter_link() {
+ <li><a href="@url" rel="ugc nofollow" >Twitter (@label)</a></li>
+ }
+ @if let Some((url, label)) = p.forum_link() {
+ <li><a href="@url" rel="ugc nofollow" >Forum (@label)</a></li>
+ }
</ul></nav>
</div>
</header>
@@ -93,9 +99,8 @@
<footer>
<div class="inner-col">
- <p>Based on data from crates-io and GitHub.</p>
+ <p>Based on data from crates-io, GitHub and <a href="https://rustaceans.org">rustaceans.org</a>.</p>
<aside role="contentinfo"><p><a href="/"><b>Lib.rs</b></a> is an unofficial list of Rust/Cargo crates. It's <a href="https://gitlab.com/crates.rs?sort=stars_desc">open-source</a>, created by <a href="/~kornelski">kornelski</a>.</p></aside>
-
</div>
</footer>
})
diff --git a/kitchen_sink/src/lib_kitchen_sink.rs b/kitchen_sink/src/lib_kitchen_sink.rs
index d10c16d..61a7357 100644
--- a/kitchen_sink/src/lib_kitchen_sink.rs
+++ b/kitchen_sink/src/lib_kitchen_sink.rs
@@ -170,6 +170,7 @@ pub struct KitchenSink {
category_overrides: HashMap<String, Vec<Cow<'static, str>>>,
crates_io_owners_cache: TempCache<Vec<CrateOwner>>,
throttle: tokio::sync::Semaphore,
+ data_path: PathBuf,
}
impl KitchenSink {
@@ -212,6 +213,7 @@ impl KitchenSink {
category_overrides: Self::load_category_overrides(&data_path.join("category_overrides.txt"))?,
crates_io_owners_cache: TempCache::new(&data_path.join("cio-owners.tmp"))?,
throttle: tokio::sync::Semaphore::new(40),
+ data_path: data_path.into(),
})
})
}
@@ -2095,6 +2097,17 @@ impl KitchenSink {
Ok(self.crate_db.recently_updated_crates_in_category(slug).await?)
}
+ /// Case sensitive!
+ pub fn rustacean_for_github_login(&self, login: &str) -> Option<Rustacean> {
+ if !is_alnum(login) {
+ return None;
+ }
+
+ let path = self.data_path.join(format!("rustaceans/data/{}.json", login));
+ let json = std::fs::read(path).ok()?;
+ serde_json::from_slice(&json).ok()
+ }
+
#[inline]
pub async fn notable_recently_updated_crates(&self, limit: u32) -> CResult<Vec<(Origin, f64)>> {
let mut crates = self.crate_db.recently_updated_crates(limit).await?;
@@ -2160,6 +2173,25 @@ impl RichAuthor {
}
}
+#[derive(Deserialize, Debug)]
+pub struct Rustacean {
+ pub name: Option<String>,
+ /// email address. Will appear in a mailto link.
+ pub email: Option<String>,
+ /// homepage URL.
+ pub website: Option<String>,
+ /// URL for your blog.
+ pub blog: Option<String>,
+ /// username on Discourse.
+ pub discourse: Option<String>,
+ /// username on Reddit
+ pub reddit: Option<String>,
+ /// username on Twitter, including the @.
+ pub twitter: Option<String>,
+ /// any notes you lik
+ pub notes: Option<String>,
+}
+
/// This is used to uniquely identify authors based on as little information as is available
#[derive(Debug, Hash, Eq, PartialEq)]
enum AuthorId {