From 575a8a29a4b025d73d0e79895b3b3d7e6f1d656c Mon Sep 17 00:00:00 2001
From: Artur Yurii Korchynskyi <42449190+akorchyn@users.noreply.github.com>
Date: Tue, 6 Aug 2024 19:12:29 +0300
Subject: [PATCH] feat: shareable image similar to bot image (#160)
@race-of-sloths
---
public/badge_share_template.svg | 224 ----------------
public/badge_share_template_dark.svg | 339 +++++++++++++++++++++++++
public/badge_share_template_white.svg | 352 ++++++++++++++++++++++++++
server/src/entrypoints/user.rs | 18 +-
server/src/svg.rs | 103 ++------
5 files changed, 726 insertions(+), 310 deletions(-)
delete mode 100644 public/badge_share_template.svg
create mode 100644 public/badge_share_template_dark.svg
create mode 100644 public/badge_share_template_white.svg
diff --git a/public/badge_share_template.svg b/public/badge_share_template.svg
deleted file mode 100644
index bf9d2ee..0000000
--- a/public/badge_share_template.svg
+++ /dev/null
@@ -1,224 +0,0 @@
-
diff --git a/public/badge_share_template_dark.svg b/public/badge_share_template_dark.svg
new file mode 100644
index 0000000..42e2351
--- /dev/null
+++ b/public/badge_share_template_dark.svg
@@ -0,0 +1,339 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {rank-svg}
+
+
+ {rank}
+
+
+ {rank-title}
+
+
+
+
+
+ {total-rating}
+
+
+ Sloth Points
+
+
+
+
+
+
+
+
+
+
+
+
+ {place}
+
+
+ {place-type} Place
+
+
+
+
+
+
+ {max-month-streak}
+
+
+ Max. month streak
+
+
+
+
+
+
+ {max-week-streak}
+
+
+ Max. week streak
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {total-contributions}
+
+
+ Total contributions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/badge_share_template_white.svg b/public/badge_share_template_white.svg
new file mode 100644
index 0000000..b2f3551
--- /dev/null
+++ b/public/badge_share_template_white.svg
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {rank-svg}
+
+
+ {rank}
+
+
+ {rank-title}
+
+
+
+
+
+ {total-rating}
+
+
+ Sloth Points
+
+
+
+
+
+
+
+
+
+
+
+
+ {place}
+
+
+ {place-type} Place
+
+
+
+
+
+
+ {max-month-streak}
+
+
+ Max. month streak
+
+
+
+
+
+
+ {max-week-streak}
+
+
+ Max. week streak
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {total-contributions}
+
+
+ Total contributions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/server/src/entrypoints/user.rs b/server/src/entrypoints/user.rs
index 30b9d1c..c3243ba 100644
--- a/server/src/entrypoints/user.rs
+++ b/server/src/entrypoints/user.rs
@@ -8,7 +8,7 @@ use race_of_sloths_server::{
DB,
},
github_pull::GithubClient,
- svg::{generate_png_meta_badge, generate_svg_bot_badge, generate_svg_share_badge, Mode},
+ svg::{generate_png_meta_badge, generate_svg_badge, Mode},
};
use rocket::{
http::{ContentType, Header, Status},
@@ -168,12 +168,12 @@ pub async fn get_badge<'a>(
return Badge::with_status(Status::InternalServerError);
}
};
- construct_svg_badge_from_result(generate_svg_bot_badge(
+ construct_svg_badge_from_result(generate_svg_badge(
telegram,
- user,
- metadata,
font.inner().clone(),
+ user,
theme.unwrap_or(Mode::Dark),
+ Some(metadata),
))
}
"meta" => {
@@ -193,9 +193,13 @@ pub async fn get_badge<'a>(
Err(_) => Badge::with_status(Status::InternalServerError),
}
}
- "share" => {
- construct_svg_badge_from_result(generate_svg_share_badge(user, font.inner().clone()))
- }
+ "share" => construct_svg_badge_from_result(generate_svg_badge(
+ telegram,
+ font.inner().clone(),
+ user,
+ theme.unwrap_or(Mode::Dark),
+ None,
+ )),
_ => {
rocket::info!("Unknown badge type {badge_type}, returning 404");
Badge::with_status(Status::NotFound)
diff --git a/server/src/svg.rs b/server/src/svg.rs
index b84b331..11da56a 100644
--- a/server/src/svg.rs
+++ b/server/src/svg.rs
@@ -13,12 +13,12 @@ pub enum Mode {
Light,
}
-pub fn generate_svg_bot_badge(
+pub fn generate_svg_badge(
telegram: &Arc,
- user_record: UserRecord,
- user_metadata: UserCachedMetadata,
fontdb: Arc,
+ user_record: UserRecord,
mode: Mode,
+ user_metadata: Option,
) -> anyhow::Result {
let all_time = TimePeriod::AllTime.time_string(0);
let total_period = user_record.get_total_period().cloned().unwrap_or_default();
@@ -53,25 +53,32 @@ pub fn generate_svg_bot_badge(
})
.unwrap_or_else(|| ("Global".to_string(), "N/A".to_string()));
- let svg_icon = match mode {
- Mode::Light => std::fs::read_to_string("./public/badge_bot_template_white.svg")?,
- Mode::Dark => std::fs::read_to_string("./public/badge_bot_template_dark.svg")?,
+ let svg_icon = match (&user_metadata, mode) {
+ (Some(_), Mode::Light) => std::fs::read_to_string("./public/badge_bot_template_white.svg")?,
+ (Some(_), Mode::Dark) => std::fs::read_to_string("./public/badge_bot_template_dark.svg")?,
+ (None, Mode::Light) => std::fs::read_to_string("./public/badge_share_template_white.svg")?,
+ (None, Mode::Dark) => std::fs::read_to_string("./public/badge_share_template_dark.svg")?,
};
- let svg_icon = image_processing(
- telegram,
- svg_icon,
- &user_metadata.image_base64,
- &user_record.login,
- );
- let sloth_id = if user_record.id == i32::MAX {
- "Newcomer".to_string()
+
+ let svg_icon = if let Some(user_metadata) = user_metadata {
+ let sloth_id = if user_record.id == i32::MAX {
+ "Newcomer".to_string()
+ } else {
+ format!("Sloth#{:04}", user_record.id)
+ };
+ image_processing(
+ telegram,
+ svg_icon,
+ &user_metadata.image_base64,
+ &user_record.login,
+ )
+ .replace("{login}", &user_record.login)
+ .replace("{sloth-id}", &sloth_id)
} else {
- format!("Sloth#{:04}", user_record.id)
+ svg_icon
};
let svg_icon = svg_icon
- .replace("{login}", &user_record.login)
- .replace("{sloth-id}", &sloth_id)
.replace(
"{total-contributions}",
&total_period.prs_opened.to_string(),
@@ -90,68 +97,6 @@ pub fn generate_svg_bot_badge(
postprocess_svg(svg_icon, fontdb)
}
-pub fn generate_svg_share_badge(
- user_record: UserRecord,
- fontdb: Arc,
-) -> anyhow::Result {
- let all_time = TimePeriod::AllTime.time_string(0);
- let total_period = user_record
- .period_data
- .iter()
- .find(|p| p.period_type == all_time)
- .cloned()
- .unwrap_or_default();
- let week_streak = user_record
- .streaks
- .iter()
- .find(|e| e.streak_type == "Weekly")
- .cloned()
- .unwrap_or_default()
- .best;
- let month_streak = user_record
- .streaks
- .iter()
- .find(|e| e.streak_type == "Monthly")
- .cloned()
- .unwrap_or_default()
- .best;
-
- let (place_type, place) = user_record
- .leaderboard_places
- .iter()
- .min_by(|(_, a), (_, b)| a.cmp(b))
- .map(|(a, place)| {
- (
- if a == &all_time {
- "Global".to_string()
- } else {
- "Monthly".to_string()
- },
- place.to_string(),
- )
- })
- .unwrap_or_else(|| ("Global".to_string(), "N/A".to_string()));
-
- let svg_icon = std::fs::read_to_string("./public/badge_share_template.svg")?;
-
- let svg_icon = svg_icon.replace(
- "{total-contributions}",
- &total_period.prs_opened.to_string(),
- );
- let svg_icon = process_rank(svg_icon, &user_record);
-
- let svg_icon = svg_icon.replace(
- "{total-rating}",
- &total_period.total_rating.to_formatted_string(&Locale::en),
- );
- let svg_icon = svg_icon.replace("{max-week-streak}", &week_streak.to_string());
- let svg_icon = svg_icon.replace("{max-month-streak}", &month_streak.to_string());
- let svg_icon = svg_icon.replace("{place}", &place);
- let svg_icon = svg_icon.replace("{place-type}", &place_type);
-
- postprocess_svg(svg_icon, fontdb)
-}
-
pub fn generate_png_meta_badge(
telegram: &Arc,
user_record: UserRecord,