···11+ALTER TABLE itemtypelookupdb RENAME TO itemtypes;
+37-3
server/src/client_communication.rs
···1717 * You may not use this work except in compliance with the Licence.
1818 * You may obtain a copy of the Licence at: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
1919 *
2020- * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED
2020+ * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED
2121 * under Art 4(3) Dir 2019/790. AI training constitutes a Derivative Work.
2222 * See LICENSE file in the repository root for full details.
2323 *
···2727 */
28282929extern crate rocket;
3030+use crate::database::DatabaseConnections;
3031use crate::errors::LuminaDbError;
3132use crate::rate_limiter::RateLimit;
3233use crate::timeline::fetch_timeline_post_ids_by_timeline_name;
3334use crate::user::User;
3435use crate::{
3536 AppState, LuminaError, authentication_error_elog, error_elog, http_code_elog, incoming_elog,
3636- info_elog, registration_error_elog,
3737+ info_elog, registration_error_elog, warn_elog,
3738};
3839use base64::Engine;
3940use base64::engine::general_purpose::STANDARD;
···5657 let appstate = state.0.clone();
5758 appstate.event_logger.clone()
5859 };
6060+ let db_pool = state.inner().0.db.get_postgres_pool();
5961 http_code_elog!(ev_log, 200, "/connection");
6062 use rocket::futures::{SinkExt, StreamExt};
6163···7981 {
8082 info_elog!(
8183 ev_log, "Post was requested: {}", post_id);
8282- todo!("PostViewRequest not yet implemented!")
8484+8585+ match crate::database::operations::get_public_timelineitem(&db_pool,post_id).await {
8686+ Ok(post) => {
8787+ let _ = match post {
8888+ crate::database::typedreturns::PostItem::TextPost{post_id,source_instance,content,timestamp}=>
8989+ {
9090+ info_elog!(
9191+ ev_log, "Serving text post {}", post_id);
9292+ stream
9393+ .send(ws::Message::from(msgtojson(Message::TextPostDataSent { post_id, source_instance, content })))
9494+ .await}
9595+ ,
9696+ crate::database::typedreturns::PostItem::MediaPost { post_id, source_instance, description, medias, timestamp } => {
9797+ info_elog!(ev_log, "Serving media post {}", post_id);
9898+9999+100100+ stream
101101+ .send(ws::Message::from(msgtojson(Message::MediaPostDataSent { post_id, source_instance, description, medias })))
102102+ .await},
103103+ crate::database::typedreturns::PostItem::ArticlePost { post_id, source_instance,title, content, timestamp,author_id, } => {
104104+ info_elog!(ev_log, "Serving article post {}", post_id);
105105+ let timestamp = todo!("Convert timestamp to unix or Rfc3339 format here?");
106106+ stream
107107+ .send(ws::Message::from(msgtojson(Message::ArticlePostDataSent { post_id, source_instance, title, content, timestamp, author_id })))
108108+ .await},
109109+ };
110110+111111+ }
112112+ Err(m) => {
113113+ warn_elog!(ev_log, "Not serving {}, {m}.", post_id);
114114+ }
115115+ };
116116+83117 }
84118 Ok(Message::Introduction { client_kind, try_revive }) => {
85119 match client_kind.as_str() {
+102-2
server/src/database.rs
···1010 * You may not use this work except in compliance with the Licence.
1111 * You may obtain a copy of the Licence at: https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
1212 *
1313- * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED
1313+ * AI TRAINING NOTICE: Rights for TDM and AI training are EXPRESSLY RESERVED
1414 * under Art 4(3) Dir 2019/790. AI training constitutes a Derivative Work.
1515 * See LICENSE file in the repository root for full details.
1616 *
···444444 Ok(())
445445}
446446447447-mod operations {
447447+pub(crate) mod operations {
448448+449449+ use std::str::FromStr;
450450+451451+ use anyhow::bail;
452452+ use time::OffsetDateTime;
453453+ use uuid::Uuid;
454454+455455+ use crate::timeline::GLOBAL_TIMELINE_ID;
456456+448457 use super::*;
449458 /// List all users and their emails from the database, used for populating bloom filters on
450459 ///startup
···469478 res.push((rec.email, rec.username));
470479 }
471480 Ok(res)
481481+ }
482482+ /// Returns a post if it is on any public timeline, including bubble timelines but excluding DM timelines.
483483+ // (This because all bubble timelines are also published to the global timeline, for now)
484484+ /// The answer from this is not necessarily safe for public API's, though it is yet unspecified how public API's would handle single postrequests.
485485+ pub(crate) async fn get_public_timelineitem(
486486+ pool: &PgPool,
487487+ postid: Uuid,
488488+ ) -> anyhow::Result<typedreturns::PostItem> {
489489+ let gltl = Uuid::from_str(GLOBAL_TIMELINE_ID)?;
490490+ let timeline_lookup = sqlx::query!(
491491+ "SELECT * FROM timelines WHERE item_id = $1 AND tlid = $2",
492492+ postid,
493493+ gltl
494494+ )
495495+ .fetch_optional(pool)
496496+ .await?;
497497+ let _ = if let None = timeline_lookup {
498498+ bail!("No post was found on global timeline")
499499+ };
500500+ let type_lookup = sqlx::query!("SELECT * FROM itemtypes WHERE item_id = $1", postid,)
501501+ .fetch_one(pool)
502502+ .await?;
503503+ match type_lookup.itemtype.as_str() {
504504+ "text" => {
505505+ let post = sqlx::query!("SELECT * FROM post_text WHERE id = $1", postid,)
506506+ .fetch_one(pool)
507507+ .await?;
508508+ let location = match (post.foreign_instance_id, post.foreign_post_id) {
509509+ (Some(pid), Some(iid)) => (Uuid::from_str(pid.as_str())?, iid),
510510+ _ => (postid, String::from("local")),
511511+ };
512512+ anyhow::Ok(typedreturns::PostItem::TextPost {
513513+ post_id: postid,
514514+ source_instance: location.1,
515515+ content: post.content,
516516+ timestamp: post.created_at,
517517+ })
518518+ }
519519+ "media" => {
520520+ todo!("Media post fetching not yet implemented.");
521521+ }
522522+ "article" => {
523523+ todo!("Article post fetching not yet implemented.");
524524+ }
525525+ _ => {
526526+ bail!("Unsupported post for the global timeline, something got mixed up here.")
527527+ }
528528+ }
529529+ }
530530+}
531531+532532+pub(crate) mod typedreturns {
533533+ use time::OffsetDateTime;
534534+ use uuid::Uuid;
535535+536536+ pub(crate) enum TimelineItem {
537537+ Post(PostItem),
538538+ }
539539+ pub(crate) enum PostItem {
540540+ ArticlePost {
541541+ post_id: Uuid,
542542+ /// Source instance. 'local' by default, hostname if external.
543543+ source_instance: String,
544544+ title: String,
545545+ content: String,
546546+ /// Timestamp of the moment of posting
547547+ timestamp: OffsetDateTime,
548548+ /// User id of poster, which is why the source_instance matters.
549549+ /// This means that client will do a lookup and stores the user once it gets it.
550550+ author_id: String,
551551+ },
552552+ MediaPost {
553553+ post_id: Uuid,
554554+ /// Source instance. 'local' by default, hostname if external.
555555+ source_instance: String,
556556+ /// Media description
557557+ description: String,
558558+ /// Base64 encoded media strings, either webp or mp4.
559559+ medias: Vec<String>,
560560+ /// Timestamp of the moment of posting
561561+ timestamp: OffsetDateTime,
562562+ },
563563+ TextPost {
564564+ post_id: Uuid,
565565+ /// Source instance. 'local' by default, hostname (IID) if external.
566566+ source_instance: String,
567567+ /// Markdown content.
568568+ content: String,
569569+ /// Timestamp of the moment of posting
570570+ timestamp: OffsetDateTime,
571571+ },
472572 }
473573}