2025-04-26 13:08:49 +01:00
|
|
|
use crate::{AuthenticatedUser, Db, endpoints::api::user::CredentialAcount, Config};
|
2025-04-11 15:47:22 +01:00
|
|
|
use rocket::{
|
2025-04-26 13:08:49 +01:00
|
|
|
State,
|
2025-04-11 15:47:22 +01:00
|
|
|
get,
|
|
|
|
serde::{Deserialize, Serialize, json::Json},
|
|
|
|
};
|
|
|
|
use rocket_db_pools::Connection;
|
|
|
|
|
|
|
|
pub type TimelineAccount = CredentialAcount;
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(crate = "rocket::serde")]
|
|
|
|
pub struct TimelineStatus {
|
2025-04-12 11:27:03 +01:00
|
|
|
pub id: String,
|
|
|
|
pub created_at: String,
|
|
|
|
pub in_reply_to_id: Option<String>,
|
|
|
|
pub in_reply_to_account_id: Option<String>,
|
|
|
|
pub content: String,
|
|
|
|
pub visibility: String,
|
|
|
|
pub spoiler_text: String,
|
|
|
|
pub sensitive: bool,
|
|
|
|
pub uri: String,
|
|
|
|
pub url: String,
|
|
|
|
pub replies_count: i64,
|
|
|
|
pub reblogs_count: i64,
|
|
|
|
pub favourites_count: i64,
|
|
|
|
pub favourited: bool,
|
|
|
|
pub reblogged: bool,
|
|
|
|
pub muted: bool,
|
|
|
|
pub bookmarked: bool,
|
2025-04-26 12:17:32 +01:00
|
|
|
pub reblog: Option<Box<TimelineStatus>>,
|
2025-04-12 11:27:03 +01:00
|
|
|
pub media_attachments: Vec<()>,
|
|
|
|
pub account: TimelineAccount,
|
2025-04-11 15:47:22 +01:00
|
|
|
}
|
|
|
|
|
2025-04-28 00:26:59 +01:00
|
|
|
#[get("/timelines/home")]
|
2025-04-24 20:19:54 +01:00
|
|
|
pub async fn home(
|
|
|
|
mut db: Connection<Db>,
|
2025-04-26 13:08:49 +01:00
|
|
|
config: &State<Config>,
|
|
|
|
_user: AuthenticatedUser,
|
2025-04-24 20:19:54 +01:00
|
|
|
) -> Json<Vec<TimelineStatus>> {
|
2025-04-28 21:06:17 +01:00
|
|
|
#[derive(sqlx::FromRow, Debug)]
|
|
|
|
struct Post {
|
|
|
|
is_boost_source: bool,
|
|
|
|
post_id: String,
|
|
|
|
user_id: String,
|
|
|
|
post_uri: String,
|
|
|
|
content: String,
|
|
|
|
created_at: String,
|
|
|
|
boosted_post_id: Option<String>,
|
|
|
|
display_name: String,
|
|
|
|
username: String
|
|
|
|
}
|
|
|
|
|
|
|
|
let posts = sqlx::query_as::<_, Post>(
|
|
|
|
r#"
|
|
|
|
WITH RECURSIVE get_home_timeline_with_boosts(
|
|
|
|
id, boosted_post_id, is_boost_source
|
|
|
|
) AS
|
|
|
|
(
|
|
|
|
SELECT p.id, p.boosted_post_id, 0 as is_boost_source
|
|
|
|
FROM post p
|
|
|
|
WHERE p.user_id IN (
|
|
|
|
SELECT u.id
|
|
|
|
FROM follow f
|
|
|
|
INNER JOIN user u ON u.actor_id = f.followed_id
|
|
|
|
WHERE f.follower_id = $1
|
|
|
|
)
|
|
|
|
UNION
|
|
|
|
SELECT p.id, p.boosted_post_id, 1 as is_boost_source
|
|
|
|
FROM post p
|
|
|
|
JOIN get_home_timeline_with_boosts tl ON tl.boosted_post_id = p.id
|
|
|
|
)
|
|
|
|
SELECT is_boost_source, p.id as "post_id", u.id as "user_id",
|
|
|
|
p.content, p.uri as "post_uri", u.username, u.display_name,
|
|
|
|
u.actor_id, p.created_at, p.boosted_post_id
|
|
|
|
FROM get_home_timeline_with_boosts
|
|
|
|
JOIN post p ON p.id = get_home_timeline_with_boosts.id
|
|
|
|
JOIN user u ON u.id = p.user_id;
|
2025-04-12 15:16:40 +01:00
|
|
|
"#
|
2025-04-11 15:47:22 +01:00
|
|
|
)
|
2025-04-28 21:06:17 +01:00
|
|
|
.bind("https://ferri.amy.mov/users/9b9d497b-2731-435f-a929-e609ca69dac9")
|
|
|
|
.fetch_all(&mut **db)
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
dbg!(&posts);
|
2025-04-11 15:47:22 +01:00
|
|
|
|
|
|
|
let mut out = Vec::<TimelineStatus>::new();
|
2025-04-28 21:06:17 +01:00
|
|
|
for record in posts.iter() {
|
2025-04-26 12:17:32 +01:00
|
|
|
let mut boost: Option<Box<TimelineStatus>> = None;
|
2025-04-28 21:06:17 +01:00
|
|
|
if let Some(ref boosted_id) = record.boosted_post_id {
|
2025-04-26 13:08:49 +01:00
|
|
|
let user_uri = config.user_url(&record.user_id);
|
2025-04-28 21:06:17 +01:00
|
|
|
let record = posts.iter().find(|p| &p.post_id == boosted_id).unwrap();
|
|
|
|
|
2025-04-26 12:17:32 +01:00
|
|
|
boost = Some(Box::new(TimelineStatus {
|
|
|
|
id: record.post_id.clone(),
|
|
|
|
created_at: record.created_at.clone(),
|
|
|
|
in_reply_to_id: None,
|
|
|
|
in_reply_to_account_id: None,
|
|
|
|
content: record.content.clone(),
|
|
|
|
visibility: "public".to_string(),
|
|
|
|
spoiler_text: "".to_string(),
|
|
|
|
sensitive: false,
|
|
|
|
uri: record.post_uri.clone(),
|
|
|
|
url: record.post_uri.clone(),
|
|
|
|
replies_count: 0,
|
|
|
|
reblogs_count: 0,
|
|
|
|
favourites_count: 0,
|
|
|
|
favourited: false,
|
|
|
|
reblogged: false,
|
|
|
|
reblog: boost,
|
|
|
|
muted: false,
|
|
|
|
bookmarked: false,
|
|
|
|
media_attachments: vec![],
|
|
|
|
account: CredentialAcount {
|
|
|
|
id: record.user_id.clone(),
|
|
|
|
username: record.username.clone(),
|
|
|
|
acct: record.username.clone(),
|
|
|
|
display_name: record.display_name.clone(),
|
|
|
|
locked: false,
|
|
|
|
bot: false,
|
|
|
|
created_at: "2025-04-10T22:12:09Z".to_string(),
|
|
|
|
attribution_domains: vec![],
|
|
|
|
note: "".to_string(),
|
|
|
|
url: user_uri,
|
|
|
|
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
followers_count: 1,
|
|
|
|
following_count: 1,
|
|
|
|
statuses_count: 1,
|
|
|
|
last_status_at: "2025-04-10T22:14:34Z".to_string(),
|
|
|
|
},
|
|
|
|
}))
|
|
|
|
}
|
2025-04-28 21:06:17 +01:00
|
|
|
|
|
|
|
if !record.is_boost_source {
|
|
|
|
let user_uri = config.user_web_url(&record.username);
|
|
|
|
out.push(TimelineStatus {
|
|
|
|
id: record.post_id.clone(),
|
|
|
|
created_at: record.created_at.clone(),
|
|
|
|
in_reply_to_id: None,
|
|
|
|
in_reply_to_account_id: None,
|
|
|
|
content: record.content.clone(),
|
|
|
|
visibility: "public".to_string(),
|
|
|
|
spoiler_text: "".to_string(),
|
|
|
|
sensitive: false,
|
|
|
|
uri: record.post_uri.clone(),
|
|
|
|
url: record.post_uri.clone(),
|
|
|
|
replies_count: 0,
|
|
|
|
reblogs_count: 0,
|
|
|
|
favourites_count: 0,
|
|
|
|
favourited: false,
|
|
|
|
reblogged: false,
|
|
|
|
reblog: boost,
|
|
|
|
muted: false,
|
|
|
|
bookmarked: false,
|
|
|
|
media_attachments: vec![],
|
|
|
|
account: CredentialAcount {
|
|
|
|
id: record.user_id.clone(),
|
|
|
|
username: record.username.clone(),
|
|
|
|
acct: record.username.clone(),
|
|
|
|
display_name: record.display_name.clone(),
|
|
|
|
locked: false,
|
|
|
|
bot: false,
|
|
|
|
created_at: "2025-04-10T22:12:09Z".to_string(),
|
|
|
|
attribution_domains: vec![],
|
|
|
|
note: "".to_string(),
|
|
|
|
url: user_uri,
|
|
|
|
avatar: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
avatar_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
header: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
header_static: "https://ferri.amy.mov/assets/pfp.png".to_string(),
|
|
|
|
followers_count: 1,
|
|
|
|
following_count: 1,
|
|
|
|
statuses_count: 1,
|
|
|
|
last_status_at: "2025-04-10T22:14:34Z".to_string(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2025-04-11 15:47:22 +01:00
|
|
|
}
|
2025-04-12 11:27:03 +01:00
|
|
|
|
2025-04-11 15:47:22 +01:00
|
|
|
Json(out)
|
|
|
|
}
|