`;
- return;
- }
+ return;
+ }
- into_element.innerHTML += `
+ into_element.innerHTML += `
@@ -929,7 +931,7 @@ media_theme_pref();
<${option.input_element_type || "input"}
type="text"
- onchange="window.set_setting_field('${option.key}', event.target.value)"
+ onchange="window.set_setting_field${id_key}('${option.key}', event.target.value)"
placeholder="${option.key}"
name="${option.key}"
id="${option.key}"
@@ -939,26 +941,37 @@ ${option.input_element_type === "textarea" ? `${option.value}` : ""}
${(option.attributes || { embed_html: "" }).embed_html}
`;
- });
+ },
+ );
self.define(
"generate_settings_ui",
({ $ }, into_element, options, settings_ref, key_map = {}) => {
+ const id_key = `a${crypto.randomUUID().replaceAll("-", "")}`;
for (const option of options) {
- $.render_settings_ui_field(into_element, {
- key: Array.isArray(option[0]) ? option[0][0] : option[0],
- label: Array.isArray(option[0]) ? option[0][1] : option[0],
- value: option[1],
- input_element_type: option[2],
- attributes: option[3],
- });
+ $.render_settings_ui_field(
+ into_element,
+ {
+ key: Array.isArray(option[0])
+ ? option[0][0]
+ : option[0],
+ label: Array.isArray(option[0])
+ ? option[0][1]
+ : option[0],
+ value: option[1],
+ input_element_type: option[2],
+ attributes: option[3],
+ },
+ id_key,
+ );
}
- window.set_setting_field = (key, value) => {
+ window[`set_setting_field${id_key}`] = (key, value) => {
if (settings_ref && !key_map[key]) {
settings_ref[key] = value;
} else {
key_map[key](value);
+ console.log("custom_update", key);
}
console.log("update", key);
diff --git a/crates/app/src/routes/pages/misc.rs b/crates/app/src/routes/pages/misc.rs
index 87bc02d..b43b9ad 100644
--- a/crates/app/src/routes/pages/misc.rs
+++ b/crates/app/src/routes/pages/misc.rs
@@ -71,7 +71,13 @@ pub async fn index_request(
{
Ok(l) => match data
.0
- .fill_posts_with_community(l, user.id, &ignore_users, &Some(user.clone()))
+ .fill_posts_with_community(
+ data.0
+ .posts_muted_phrase_filter(&l, Some(&user.settings.muted)),
+ user.id,
+ &ignore_users,
+ &Some(user.clone()),
+ )
.await
{
Ok(l) => l,
@@ -103,7 +109,14 @@ pub async fn popular_request(
Ok(l) => match data
.0
.fill_posts_with_community(
- l,
+ data.0.posts_muted_phrase_filter(
+ &l,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -149,7 +162,13 @@ pub async fn following_request(
{
Ok(l) => match data
.0
- .fill_posts_with_community(l, user.id, &ignore_users, &Some(user.clone()))
+ .fill_posts_with_community(
+ data.0
+ .posts_muted_phrase_filter(&l, Some(&user.settings.muted)),
+ user.id,
+ &ignore_users,
+ &Some(user.clone()),
+ )
.await
{
Ok(l) => l,
@@ -183,7 +202,14 @@ pub async fn all_request(
Ok(l) => match data
.0
.fill_posts_with_community(
- l,
+ data.0.posts_muted_phrase_filter(
+ &l,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -580,7 +606,13 @@ pub async fn search_request(
{
Ok(l) => match data
.0
- .fill_posts_with_community(l, user.id, &ignore_users, &Some(user.clone()))
+ .fill_posts_with_community(
+ data.0
+ .posts_muted_phrase_filter(&l, Some(&user.settings.muted)),
+ user.id,
+ &ignore_users,
+ &Some(user.clone()),
+ )
.await
{
Ok(l) => l,
@@ -592,7 +624,13 @@ pub async fn search_request(
match data.0.get_posts_searched(12, req.page, &req.query).await {
Ok(l) => match data
.0
- .fill_posts_with_community(l, user.id, &ignore_users, &Some(user.clone()))
+ .fill_posts_with_community(
+ data.0
+ .posts_muted_phrase_filter(&l, Some(&user.settings.muted)),
+ user.id,
+ &ignore_users,
+ &Some(user.clone()),
+ )
.await
{
Ok(l) => l,
diff --git a/crates/app/src/routes/pages/profile.rs b/crates/app/src/routes/pages/profile.rs
index ef48326..86b8401 100644
--- a/crates/app/src/routes/pages/profile.rs
+++ b/crates/app/src/routes/pages/profile.rs
@@ -245,7 +245,14 @@ pub async fn posts_request(
Ok(p) => match data
.0
.fill_posts_with_community(
- p,
+ data.0.posts_muted_phrase_filter(
+ &p,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -266,7 +273,14 @@ pub async fn posts_request(
Ok(p) => match data
.0
.fill_posts_with_community(
- p,
+ data.0.posts_muted_phrase_filter(
+ &p,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -285,7 +299,14 @@ pub async fn posts_request(
Ok(p) => match data
.0
.fill_posts_with_community(
- p,
+ data.0.posts_muted_phrase_filter(
+ &p,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -394,7 +415,14 @@ pub async fn replies_request(
Ok(p) => match data
.0
.fill_posts_with_community(
- p,
+ data.0.posts_muted_phrase_filter(
+ &p,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
@@ -500,7 +528,14 @@ pub async fn media_request(
Ok(p) => match data
.0
.fill_posts_with_community(
- p,
+ data.0.posts_muted_phrase_filter(
+ &p,
+ if let Some(ref ua) = user {
+ Some(&ua.settings.muted)
+ } else {
+ None
+ },
+ ),
if let Some(ref ua) = user { ua.id } else { 0 },
&ignore_users,
&user,
diff --git a/crates/core/src/database/posts.rs b/crates/core/src/database/posts.rs
index 5bda172..aa0265c 100644
--- a/crates/core/src/database/posts.rs
+++ b/crates/core/src/database/posts.rs
@@ -21,8 +21,20 @@ use oiseau::SqliteRow;
#[cfg(feature = "postgres")]
use oiseau::PostgresRow;
+#[cfg(feature = "redis")]
+use oiseau::cache::redis::Commands;
+
use oiseau::{execute, get, query_row, query_rows, params};
+pub type FullPost = (
+ Post,
+ User,
+ Community,
+ Option<(User, Post)>,
+ Option<(Question, User)>,
+ Option<(Poll, bool, bool)>,
+);
+
macro_rules! private_post_replying {
($post:ident, $replying_posts:ident, $ua1:ident, $data:ident) => {
// post owner is not following us
@@ -376,16 +388,7 @@ impl DataManager {
user_id: usize,
ignore_users: &[usize],
user: &Option
,
- ) -> Result<
- Vec<(
- Post,
- User,
- Community,
- Option<(User, Post)>,
- Option<(Question, User)>,
- Option<(Poll, bool, bool)>,
- )>,
- > {
+ ) -> Result> {
let mut out = Vec::new();
let mut seen_before: HashMap<(usize, usize), (User, Community)> = HashMap::new();
@@ -463,6 +466,33 @@ impl DataManager {
Ok(out)
}
+ /// Update posts which contain a muted phrase.
+ pub fn posts_muted_phrase_filter(
+ &self,
+ posts: &Vec,
+ muted: Option<&Vec>,
+ ) -> Vec {
+ let muted = match muted {
+ Some(m) => m,
+ None => return posts.to_owned(),
+ };
+
+ let mut out: Vec = Vec::new();
+
+ for mut post in posts.clone() {
+ for phrase in muted {
+ if post.content.contains(phrase) {
+ post.context.content_warning = "Contains muted phrase".to_string();
+ break;
+ }
+ }
+
+ out.push(post);
+ }
+
+ out
+ }
+
/// Get all posts from the given user (from most recent).
///
/// # Arguments
@@ -533,7 +563,7 @@ impl DataManager {
let res = query_rows!(
&conn,
- &format!("SELECT * FROM posts WHERE owner = $1 ORDER BY created DESC LIMIT 50"),
+ &format!("SELECT * FROM posts WHERE owner = $1 ORDER BY created DESC LIMIT 12"),
&[&(id as i64)],
|x| { Self::get_post_from_row(x) }
);
@@ -581,11 +611,21 @@ impl DataManager {
let gpa = (good_posts as f32 / real_posts_count as f32) * 4.0;
let gpa_rounded = format!("{gpa:.2}").parse::().unwrap();
- self.0
- .1
- .set(format!("atto.user.gpa:{}", id), gpa_rounded.to_string())
- .await;
+ let mut redis_con = self.0.1.get_con().await;
+ // expires in one day
+ if redis_con
+ .set_ex::(
+ format!("atto.user.gpa:{}", id),
+ gpa_rounded.to_string(),
+ 86400,
+ )
+ .is_err()
+ {
+ return 0.0;
+ };
+
+ // ...
gpa_rounded
}
diff --git a/crates/core/src/model/auth.rs b/crates/core/src/model/auth.rs
index 425a8be..c99bdaf 100644
--- a/crates/core/src/model/auth.rs
+++ b/crates/core/src/model/auth.rs
@@ -225,6 +225,12 @@ pub struct UserSettings {
/// If extra post tabs are hidden (replies, media).
#[serde(default)]
pub hide_extra_post_tabs: bool,
+ /// If the GPA experiment is disabled.
+ #[serde(default)]
+ pub disable_gpa_fun: bool,
+ /// A list of strings the user has muted.
+ #[serde(default)]
+ pub muted: Vec,
}
fn mime_avif() -> String {