add: hide_social_follows setting
This commit is contained in:
parent
e78c43ab62
commit
a337e0c7c1
11 changed files with 179 additions and 96 deletions
|
@ -4,15 +4,11 @@ use nanoneo::{
|
|||
};
|
||||
use pathbufd::PathBufD;
|
||||
use regex::Regex;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{exists, read_to_string, write},
|
||||
sync::LazyLock,
|
||||
time::SystemTime,
|
||||
};
|
||||
use std::{collections::HashMap, fs::read_to_string, sync::LazyLock, time::SystemTime};
|
||||
use tera::Context;
|
||||
use tetratto_core::{
|
||||
config::Config,
|
||||
html::{pull_icons, ICONS},
|
||||
model::{
|
||||
auth::{DefaultTimelineChoice, User},
|
||||
permissions::{FinePermission, SecondaryPermission},
|
||||
|
@ -157,38 +153,6 @@ pub const TETRATTO_BUNNY: &[u8] = include_bytes!("./public/images/tetratto_bunny
|
|||
pub(crate) static HTML_FOOTER: LazyLock<RwLock<String>> =
|
||||
LazyLock::new(|| RwLock::new(String::new()));
|
||||
|
||||
/// A container for all loaded icons.
|
||||
pub(crate) static ICONS: LazyLock<RwLock<HashMap<String, String>>> =
|
||||
LazyLock::new(|| RwLock::new(HashMap::new()));
|
||||
|
||||
/// Pull an icon given its name and insert it into [`ICONS`].
|
||||
pub(crate) async fn pull_icon(icon: &str, icons_dir: &str) {
|
||||
let writer = &mut ICONS.write().await;
|
||||
|
||||
let icon_url = format!(
|
||||
"https://raw.githubusercontent.com/lucide-icons/lucide/refs/heads/main/icons/{icon}.svg"
|
||||
);
|
||||
|
||||
let file_path = PathBufD::current().extend(&[icons_dir, &format!("{icon}.svg")]);
|
||||
|
||||
if exists(&file_path).unwrap() {
|
||||
writer.insert(icon.to_string(), read_to_string(&file_path).unwrap());
|
||||
return;
|
||||
}
|
||||
|
||||
println!("download icon: {icon}");
|
||||
let svg = reqwest::get(icon_url)
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
.replace("\n", "");
|
||||
|
||||
write(&file_path, &svg).unwrap();
|
||||
writer.insert(icon.to_string(), svg);
|
||||
}
|
||||
|
||||
macro_rules! vendor_icon {
|
||||
($name:literal, $icon:ident, $icons_dir:expr) => {{
|
||||
let writer = &mut ICONS.write().await;
|
||||
|
@ -261,56 +225,8 @@ pub(crate) async fn replace_in_html(
|
|||
input = input.replace(cap.get(0).unwrap().as_str(), &replace_with);
|
||||
}
|
||||
|
||||
// icon (with class)
|
||||
let icon_with_class =
|
||||
Regex::new("(\\{\\{)\\s*(icon)\\s*(.*?)\\s*c\\((.*?)\\)\\s*(\\}\\})").unwrap();
|
||||
|
||||
for cap in icon_with_class.captures_iter(&input.clone()) {
|
||||
let cap_str = &cap.get(3).unwrap().as_str().replace("\"", "");
|
||||
let icon = &(if cap_str.contains(" }}") {
|
||||
cap_str.split(" }}").next().unwrap().to_string()
|
||||
} else {
|
||||
cap_str.to_string()
|
||||
});
|
||||
|
||||
pull_icon(icon, &config.dirs.icons).await;
|
||||
|
||||
let reader = ICONS.read().await;
|
||||
let icon_text = reader.get(icon).unwrap().replace(
|
||||
"<svg",
|
||||
&format!("<svg class=\"icon {}\"", cap.get(4).unwrap().as_str()),
|
||||
);
|
||||
|
||||
input = input.replace(
|
||||
&format!(
|
||||
"{{{{ icon \"{cap_str}\" c({}) }}}}",
|
||||
cap.get(4).unwrap().as_str()
|
||||
),
|
||||
&icon_text,
|
||||
);
|
||||
}
|
||||
|
||||
// icon (without class)
|
||||
let icon_without_class = Regex::new("(\\{\\{)\\s*(icon)\\s*(.*?)\\s*(\\}\\})").unwrap();
|
||||
|
||||
for cap in icon_without_class.captures_iter(&input.clone()) {
|
||||
let cap_str = &cap.get(3).unwrap().as_str().replace("\"", "");
|
||||
let icon = &(if cap_str.contains(" }}") {
|
||||
cap_str.split(" }}").next().unwrap().to_string()
|
||||
} else {
|
||||
cap_str.to_string()
|
||||
});
|
||||
|
||||
pull_icon(icon, &config.dirs.icons).await;
|
||||
|
||||
let reader = ICONS.read().await;
|
||||
let icon_text = reader
|
||||
.get(icon)
|
||||
.unwrap()
|
||||
.replace("<svg", "<svg class=\"icon\"");
|
||||
|
||||
input = input.replace(&format!("{{{{ icon \"{cap_str}\" }}}}",), &icon_text);
|
||||
}
|
||||
// icons
|
||||
input = pull_icons(input, &config.dirs.icons).await;
|
||||
|
||||
// return
|
||||
input = input.replacen("<!-- html_footer_goes_here -->", &format!("{reader}"), 1);
|
||||
|
|
|
@ -107,6 +107,7 @@
|
|||
(p
|
||||
(text "{{ profile.settings.status }}"))
|
||||
(text "{%- endif %}")
|
||||
(text "{% if not profile.settings.hide_social_follows or (user and user.id == profile.id) -%}")
|
||||
(div
|
||||
("class" "w-full flex")
|
||||
(a
|
||||
|
@ -123,6 +124,7 @@
|
|||
(text "{{ profile.following_count }}"))
|
||||
(span
|
||||
(text "{{ text \"auth:label.following\" }}"))))
|
||||
(text "{%- endif %}")
|
||||
(text "{% if is_following_you -%}")
|
||||
(b
|
||||
("class" "notification chip w-content flex items-center gap-2")
|
||||
|
|
|
@ -1889,6 +1889,14 @@
|
|||
\"{{ profile.settings.hide_from_social_lists }}\",
|
||||
\"checkbox\",
|
||||
],
|
||||
[
|
||||
[
|
||||
\"hide_social_follows\",
|
||||
\"Hide followers/following links on my profile\",
|
||||
],
|
||||
\"{{ profile.settings.hide_social_follows }}\",
|
||||
\"checkbox\",
|
||||
],
|
||||
[[], \"Questions\", \"title\"],
|
||||
[
|
||||
[
|
||||
|
|
|
@ -731,6 +731,21 @@ pub async fn following_request(
|
|||
|
||||
check_user_blocked_or_private!(user, other_user, data, jar);
|
||||
|
||||
// check hide_social_follows
|
||||
if other_user.settings.hide_social_follows {
|
||||
if let Some(ref ua) = user {
|
||||
if ua.id != other_user.id {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// fetch data
|
||||
let list = match data
|
||||
.0
|
||||
|
@ -826,6 +841,21 @@ pub async fn followers_request(
|
|||
|
||||
check_user_blocked_or_private!(user, other_user, data, jar);
|
||||
|
||||
// check hide_social_follows
|
||||
if other_user.settings.hide_social_follows {
|
||||
if let Some(ref ua) = user {
|
||||
if ua.id != other_user.id {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Html(
|
||||
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// fetch data
|
||||
let list = match data
|
||||
.0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue