~boringcactus/gemifedi

2e83fd419121a7de2b385e21b3f72e43e93885a5 — Melody Horn 1 year, 2 months ago d860db4
add post context & actions
1 files changed, 111 insertions(+), 29 deletions(-)

M src/main.rs
M src/main.rs => src/main.rs +111 -29
@@ 1,5 1,6 @@
use std::{
    fs::{self, File, create_dir_all},
    iter,
    io::BufReader,
    path::PathBuf,
    sync::Arc,


@@ 31,7 32,15 @@ use gemini_util::*;
mod mastodon_util;
use mastodon_util::*;

fn render_post(post: elefren::entities::status::Status) -> Vec<gemtext::Node> {
fn undo_prefix(did: Option<bool>) -> &'static str {
    if did.unwrap_or(false) {
        "un"
    } else {
        ""
    }
}

fn render_post(post: elefren::entities::status::Status, highlight: bool) -> Vec<gemtext::Node> {
    let reply_info = match post.in_reply_to_account_id {
        Some(account) => {
            let replyee = if account == post.account.id {


@@ 64,14 73,30 @@ fn render_post(post: elefren::entities::status::Status) -> Vec<gemtext::Node> {
        reblog_info=reblog_info,
    );

    let heading_level = if highlight {
        2
    } else {
        3
    };
    let detail_link = if highlight { post.url } else { None }.unwrap_or(format!("/status/{}", post.id));
    let mut result = vec![
        gemtext::Node::Heading { level: 3, body: post_info },
        gemtext::Node::Heading { level: heading_level, body: post_info },
    ];

    let post_actions = if highlight {
        gemtext::Builder::new()
            .link("?reply", Some("reply".to_string()))
            .link("?boost", Some(format!("{}boost", undo_prefix(post.reblogged))))
            .link("?fav", Some(format!("{}favorite", undo_prefix(post.favourited))))
            .build()
    } else {
        vec![]
    };

    result.extend(strip_html(&post.content));
    result.extend(vec![
        gemtext::Node::Link { to: format!("/status/{}", post.id), name: None },
        gemtext::Node::blank(),
    ]);
    result.push(gemtext::Node::Link { to: detail_link, name: None });
    result.extend(post_actions);
    result.push(gemtext::Node::blank());
    result
}



@@ 113,7 138,7 @@ impl Handler {

        let posts = home.items_iter()
            .take(10)
            .flat_map(render_post);
            .flat_map(|post| render_post(post, false));

        let body = before_timeline.into_iter()
            .chain(posts)


@@ 123,17 148,17 @@ impl Handler {
    }

    fn post(&self, req: GeminiRequest) -> Result<GeminiResponse, Error> {
        let path = mastodon_data_path(&req);
        let path = match path {
            Some(path) => path,
            None => return Ok(GeminiResponse::need_cert("Need a cert to be able to log in!"))
        };
        let mastodon = match mastodon_toml::from_file(path) {
            Ok(data) => Mastodon::from(data),
            Err(_) => return Ok(temp_redirect("/auth"))
        };
        match req.url.query() {
            Some(post) => {
                let path = mastodon_data_path(&req);
                let path = match path {
                    Some(path) => path,
                    None => return Ok(GeminiResponse::need_cert("Need a cert to be able to log in!"))
                };
                let mastodon = match mastodon_toml::from_file(path) {
                    Ok(data) => Mastodon::from(data),
                    Err(_) => return Ok(temp_redirect("/auth"))
                };
                let post = percent_encoding::percent_decode_str(post).decode_utf8_lossy();
                let new_status = StatusBuilder::new()
                    .status(post)


@@ 143,15 168,6 @@ impl Handler {
                Ok(temp_redirect(format!("/status/{}", status.id)))
            }
            None => {
                let path = mastodon_data_path(&req);
                let path = match path {
                    Some(path) => path,
                    None => return Ok(GeminiResponse::need_cert("Need a cert to be able to log in!"))
                };
                let _mastodon = match mastodon_toml::from_file(path) {
                    Ok(data) => Mastodon::from(data),
                    Err(_) => return Ok(temp_redirect("/auth"))
                };
                Ok(GeminiResponse::input(format!("Post some text")))
            }
        }


@@ 221,10 237,75 @@ impl Handler {
            Err(_) => return Ok(temp_redirect("/auth"))
        };

        Ok(match mastodon.get_status(id) {
            Ok(status) => GeminiResponse::render(apply_global_template(render_post(status))),
            Err(_) => GeminiResponse::not_found(),
        })
        let status = mastodon.get_status(id);
        let context = mastodon.get_context(id);
        let (status, context) = match (status, context) {
            (Ok(status), Ok(context)) => (status, context),
            _ => return Ok(GeminiResponse::not_found()),
        };

        match req.url.query() {
            Some("reply") => {
                return Ok(temp_redirect(format!("/status/{}/reply", id)));
            }
            Some("boost") => {
                let action = if status.reblogged.unwrap_or(false) {
                    mastodon.unreblog(id)
                } else {
                    mastodon.reblog(id)
                };
                action.unwrap();
                return Ok(temp_redirect(format!("/status/{}", id)));
            }
            Some("fav") => {
                let action = if status.favourited.unwrap_or(false) {
                    mastodon.unfavourite(id)
                } else {
                    mastodon.favourite(id)
                };
                action.unwrap();
                return Ok(temp_redirect(format!("/status/{}", id)));
            }
            _ => {}
        }

        let posts = context.ancestors.into_iter()
            .chain(iter::once(status))
            .chain(context.descendants)
            .flat_map(|post| {
                let highlight = post.id == id;
                render_post(post, highlight)
            })
            .collect();

        Ok(GeminiResponse::render(apply_global_template(posts)))
    }

    fn reply(&self, req: GeminiRequest, id: &str) -> Result<GeminiResponse, Error> {
        let path = mastodon_data_path(&req);
        let path = match path {
            Some(path) => path,
            None => return Ok(GeminiResponse::need_cert("Need a cert to be able to log in!"))
        };
        let mastodon = match mastodon_toml::from_file(path) {
            Ok(data) => Mastodon::from(data),
            Err(_) => return Ok(temp_redirect("/auth"))
        };
        match req.url.query() {
            Some(post) => {
                let post = percent_encoding::percent_decode_str(post).decode_utf8_lossy();
                let new_status = StatusBuilder::new()
                    .status(post)
                    .in_reply_to(id)
                    .build()
                    .unwrap();
                let status = mastodon.new_status(new_status).unwrap();
                Ok(temp_redirect(format!("/status/{}", status.id)))
            }
            None => {
                Ok(GeminiResponse::input(format!("Reply with some text")))
            }
        }
    }

    fn about(&self, _req: GeminiRequest) -> Result<GeminiResponse, Error> {


@@ 264,6 345,7 @@ impl GeminiHandler for Handler {
            (/"auth"/[instance]/"code") => self.auth_finish(req, instance);
            (/"logout")                 => self.logout(req);
            (/"status"/[id])            => self.status(req, id);
            (/"status"/[id]/"reply")    => self.reply(req, id);
            (/"about")                  => self.about(req);
        });
        Ok(GeminiResponse::not_found())