diff --git a/src/routes/contact.rs b/src/routes/contact.rs index ba9d44b..33f0973 100644 --- a/src/routes/contact.rs +++ b/src/routes/contact.rs @@ -2,6 +2,7 @@ use actix_web::{get, routes, web, HttpRequest, HttpResponse, Responder}; use cached::proc_macro::once; use glob::glob; use ramhorns::Content; +use std::fs::read_to_string; use crate::{ config::Config, @@ -32,49 +33,75 @@ async fn page(req: HttpRequest, config: web::Data) -> impl Responder { )) } +#[derive(Clone, Debug)] +struct ContactLink { + service: String, + scope: Option, + link: String, +} + +#[once(time = 60)] +fn find_links() -> Vec { + // TOML file location + let contacts_dir = "data/contacts"; + let toml_file = "links.toml"; + + // Read the TOML file and parse it + let toml_str = read_to_string(format!("{contacts_dir}/{toml_file}")).unwrap_or_default(); + + let mut redirections = vec![]; + match toml::de::from_str::(&toml_str) { + Ok(data) => { + if let Some(section) = data.as_table() { + section.iter().for_each(|(key, value)| { + // Scopes are delimited with `/` + let (service, scope) = match key.split_once('/') { + Some((service, scope)) => (service.to_owned(), Some(scope.to_owned())), + None => (key.to_owned(), None), + }; + + redirections.push(ContactLink { + service, + scope, + link: value.as_str().unwrap().to_owned(), + }); + }); + } + } + Err(_) => return vec![], + } + + redirections +} + #[routes] #[get("/{service}")] #[get("/{service}/{scope}")] async fn service_redirection(req: HttpRequest) -> impl Responder { let info = req.match_info(); - let find_redirection = match info.query("service") { - // TODO: XML file with link, so it's not hardcoded here + let link = find_links() + .iter() + // Find requested service + .filter(|&x| x.service == *info.query("service")) + // Search for a potential scope + .filter(|&x| match (info.get("scope"), x.scope.to_owned()) { + // The right scope is accepted + (Some(str_value), Some(string_value)) if str_value == string_value.as_str() => true, + // No scope provided is accepted + (None, None) => true, + // Else we reject + _ => false, + }) + // Returns the link + .map(|data| data.link.clone()) + .collect::>(); - /* Socials links */ - "twitter" => Some("https://twitter.com/Mylloon".to_owned()), - "mastodon" => Some("https://piaille.fr/@mylloon".to_owned()), - "bluesky" => Some("https://bsky.app/profile/mylloon.fr".to_owned()), - "discord" => match info.get("scope") { - Some("user") => Some("https://discord.com/users/158260864623968257/".to_owned()), - Some("guild") => Some("https://discord.gg/Z5ePxH4".to_owned()), - _ => None, - }, - "reddit" => Some("https://www.reddit.com/user/mylloon".to_owned()), - "instagram" => Some("https://www.instagram.com/mylloon/".to_owned()), - "kitsu" => Some("https://kitsu.io/users/Mylloon/library?status=completed".to_owned()), - "steam" => Some("https://steamcommunity.com/id/mylloon/".to_owned()), - "youtube" => Some("https://www.youtube.com/c/Mylloon".to_owned()), - "twitch" => Some("https://www.twitch.tv/mylloon".to_owned()), - - /* Forges */ - "github" => Some("https://github.com/Mylloon".to_owned()), - "gitlab" => Some("https://gitlab.com/Mylloon".to_owned()), - "codeberg" => Some("https://codeberg.org/Mylloon".to_owned()), - "forgejo" => Some("https://git.mylloon.fr/Anri".to_owned()), - - /* Others */ - "keyoxide" => { - Some("https://keyoxide.org/27024A99057E58B8087A5022A82D63DFF8D1317F".to_owned()) - } - _ => None, - }; - - if let Some(redirection) = find_redirection { + // This shouldn't be more than one link here + match link.len() { // Redirect to the desired service - actix_web::web::Redirect::to(redirection) - } else { + 1 => actix_web::web::Redirect::to(link[0].clone()), // By default, returns to the contact page - actix_web::web::Redirect::to("/contact") + _ => actix_web::web::Redirect::to("/contact"), } }