~vpzom/hitide

617075ab5675c8a4d0075982d806dc9e0d831cdd — Colin Reeder 2 months ago b494891 new-replies-api
Fix API calls for new replies API
4 files changed, 151 insertions(+), 21 deletions(-)

M src/components/mod.rs
M src/resp_types.rs
M src/routes/mod.rs
M src/routes/posts.rs
M src/components/mod.rs => src/components/mod.rs +19 -6
@@ 92,24 92,37 @@ pub fn Comment<'a>(

            {
                if let Some(replies) = &comment.replies {
                    if replies.items.is_empty() {
                        None
                    } else {
                        Some(render::rsx! {
                            <ul class={"commentList"}>
                            <>
                                <ul class={"commentList"}>
                                    {
                                        replies.items.iter().map(|reply| {
                                            render::rsx! {
                                                <Comment comment={reply} base_data lang />
                                            }
                                        })
                                        .collect::<Vec<_>>()
                                    }
                                </ul>
                                {
                                    replies.iter().map(|reply| {
                                    replies.next_page.as_ref().map(|next_page| {
                                        render::rsx! {
                                            <Comment comment={reply} base_data lang />
                                            <a href={format!("/comments/{}?page={}", comment.base.id, next_page)}>{"-> "}{lang.tr("view_more_comments", None)}</a>
                                        }
                                    })
                                    .collect::<Vec<_>>()
                                }
                            </ul>
                            </>
                        })
                    }
                } else {
                    None
                }
            }
            {
                if comment.replies.is_none() && comment.has_replies {
                if comment.replies.is_none() {
                    Some(render::rsx! {
                        <ul><li><a href={format!("/comments/{}", comment.as_ref().id)}>{"-> "}{lang.tr("view_more_comments", None)}</a></li></ul>
                    })

M src/resp_types.rs => src/resp_types.rs +1 -4
@@ 98,8 98,7 @@ pub struct RespPostCommentInfo<'a> {
    pub local: bool,
    pub your_vote: Option<Empty>,
    #[serde(borrow)]
    pub replies: Option<Vec<RespPostCommentInfo<'a>>>,
    pub has_replies: bool,
    pub replies: Option<RespList<'a, RespPostCommentInfo<'a>>>,
}

impl<'a> AsRef<RespMinimalCommentInfo<'a>> for RespPostCommentInfo<'a> {


@@ 134,8 133,6 @@ pub struct RespPostInfo<'a> {
    pub approved: bool,
    pub score: i64,
    pub local: bool,
    #[serde(borrow)]
    pub replies: Vec<RespPostCommentInfo<'a>>,
    pub your_vote: Option<Empty>,
}


M src/routes/mod.rs => src/routes/mod.rs +67 -8
@@ 1,4 1,4 @@
use serde_derive::Deserialize;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;


@@ 8,8 8,8 @@ use crate::components::{
    PostItem, ThingItem, UserLink,
};
use crate::resp_types::{
    JustStringID, RespCommentInfo, RespInstanceInfo, RespNotification, RespPostCommentInfo,
    RespPostListPost, RespThingInfo, RespUserInfo,
    JustStringID, RespCommentInfo, RespInstanceInfo, RespList, RespNotification,
    RespPostCommentInfo, RespPostListPost, RespThingInfo, RespUserInfo,
};
use crate::util::{abbreviate_link, author_is_me};
use crate::PageBaseData;


@@ 191,21 191,39 @@ async fn page_comment(

    let cookies = get_cookie_map_for_req(&req)?;

    page_comment_inner(comment_id, req.headers(), &cookies, ctx, None, None).await
    page_comment_inner(
        comment_id,
        req.headers(),
        req.uri().query(),
        &cookies,
        ctx,
        None,
        None,
    )
    .await
}

async fn page_comment_inner(
    comment_id: i64,
    headers: &hyper::header::HeaderMap,
    query: Option<&str>,
    cookies: &CookieMap<'_>,
    ctx: Arc<crate::RouteContext>,
    display_error: Option<String>,
    prev_values: Option<&HashMap<Cow<'_, str>, serde_json::Value>>,
) -> Result<hyper::Response<hyper::Body>, crate::Error> {
    let lang = crate::get_lang_for_headers(headers);

    #[derive(Deserialize)]
    struct Query<'a> {
        page: Option<Cow<'a, str>>,
    }

    let query: Query = serde_urlencoded::from_str(query.unwrap_or(""))?;

    let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, headers, &cookies).await?;

    let api_res = res_to_error(
    let info_api_res = res_to_error(
        ctx.http_client
            .request(for_client(
                hyper::Request::get(format!(


@@ 225,8 243,40 @@ async fn page_comment_inner(
            .await?,
    )
    .await?;
    let api_res = hyper::body::to_bytes(api_res.into_body()).await?;
    let comment: RespCommentInfo<'_> = serde_json::from_slice(&api_res)?;
    let info_api_res = hyper::body::to_bytes(info_api_res.into_body()).await?;
    let comment: RespCommentInfo<'_> = serde_json::from_slice(&info_api_res)?;

    #[derive(Serialize)]
    struct RepliesListQuery<'a> {
        include_your: Option<bool>,
        page: Option<&'a str>,
    }
    let replies_req_query = RepliesListQuery {
        include_your: if base_data.login.is_some() {
            Some(true)
        } else {
            None
        },
        page: query.page.as_deref(),
    };
    let replies_req_query = serde_urlencoded::to_string(&replies_req_query)?;

    let replies_api_res = res_to_error(
        ctx.http_client
            .request(for_client(
                hyper::Request::get(format!(
                    "{}/api/unstable/comments/{}/replies?{}",
                    ctx.backend_host, comment_id, replies_req_query,
                ))
                .body(Default::default())?,
                headers,
                &cookies,
            )?)
            .await?,
    )
    .await?;
    let replies_api_res = hyper::body::to_bytes(replies_api_res.into_body()).await?;
    let replies: RespList<RespPostCommentInfo<'_>> = serde_json::from_slice(&replies_api_res)?;

    let title = lang.tr("comment", None);



@@ 337,13 387,20 @@ async fn page_comment_inner(
            }
            <ul class={"commentList topLevel"}>
                {
                    comment.as_ref().replies.as_ref().unwrap().iter().map(|reply| {
                    replies.items.iter().map(|reply| {
                        render::rsx! {
                            <Comment comment={reply} base_data={&base_data} lang={&lang} />
                        }
                    }).collect::<Vec<_>>()
                }
            </ul>
            {
                replies.next_page.as_ref().map(|next_page| {
                    render::rsx! {
                        <a href={format!("/comments/{}?page={}", comment.base.base.id, next_page)}>{"-> "}{lang.tr("view_more_comments", None)}</a>
                    }
                })
            }
        </HTPage>
    }))
}


@@ 682,6 739,7 @@ async fn handler_comment_submit_reply(
            return page_comment_inner(
                comment_id,
                &req_parts.headers,
                None,
                &cookies,
                ctx,
                Some(error),


@@ 715,6 773,7 @@ async fn handler_comment_submit_reply(
            page_comment_inner(
                comment_id,
                &req_parts.headers,
                None,
                &cookies,
                ctx,
                Some(message),

M src/routes/posts.rs => src/routes/posts.rs +64 -3
@@ 6,8 6,11 @@ use super::{
use crate::components::{
    Comment, CommunityLink, Content, HTPage, IconExt, MaybeFillTextArea, TimeAgo, UserLink,
};
use crate::resp_types::{JustUser, RespCommunityInfoMaybeYour, RespList, RespPostInfo};
use crate::resp_types::{
    JustUser, RespCommunityInfoMaybeYour, RespList, RespPostCommentInfo, RespPostInfo,
};
use crate::util::author_is_me;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;


@@ 21,12 24,22 @@ async fn page_post(

    let cookies = get_cookie_map_for_req(&req)?;

    page_post_inner(post_id, req.headers(), &cookies, ctx, None, None).await
    page_post_inner(
        post_id,
        req.headers(),
        req.uri().query(),
        &cookies,
        ctx,
        None,
        None,
    )
    .await
}

async fn page_post_inner(
    post_id: i64,
    headers: &hyper::header::HeaderMap,
    query: Option<&str>,
    cookies: &CookieMap<'_>,
    ctx: Arc<crate::RouteContext>,
    display_error: Option<String>,


@@ 34,6 47,13 @@ async fn page_post_inner(
) -> Result<hyper::Response<hyper::Body>, crate::Error> {
    let lang = crate::get_lang_for_headers(headers);

    #[derive(Deserialize)]
    struct Query<'a> {
        page: Option<Cow<'a, str>>,
    }

    let query: Query = serde_urlencoded::from_str(query.unwrap_or(""))?;

    let base_data = fetch_base_data(&ctx.backend_host, &ctx.http_client, headers, &cookies).await?;

    let api_res = res_to_error(


@@ 59,6 79,38 @@ async fn page_post_inner(
    let api_res = hyper::body::to_bytes(api_res.into_body()).await?;
    let post: RespPostInfo = serde_json::from_slice(&api_res)?;

    #[derive(Serialize)]
    struct RepliesListQuery<'a> {
        include_your: Option<bool>,
        page: Option<&'a str>,
    }
    let api_req_query = RepliesListQuery {
        include_your: if base_data.login.is_some() {
            Some(true)
        } else {
            None
        },
        page: query.page.as_deref(),
    };
    let api_req_query = serde_urlencoded::to_string(&api_req_query)?;

    let replies_api_res = res_to_error(
        ctx.http_client
            .request(for_client(
                hyper::Request::get(format!(
                    "{}/api/unstable/posts/{}/replies?{}",
                    ctx.backend_host, post_id, api_req_query,
                ))
                .body(Default::default())?,
                headers,
                &cookies,
            )?)
            .await?,
    )
    .await?;
    let replies_api_res = hyper::body::to_bytes(replies_api_res.into_body()).await?;
    let replies: RespList<RespPostCommentInfo> = serde_json::from_slice(&replies_api_res)?;

    let is_community_moderator = if base_data.login.is_some() {
        let api_res = res_to_error(
            ctx.http_client


@@ 208,13 260,20 @@ async fn page_post_inner(
                }
                <ul class={"commentList topLevel"}>
                    {
                        post.replies.iter().map(|comment| {
                        replies.items.iter().map(|comment| {
                            render::rsx! {
                                <Comment comment={comment} base_data={&base_data} lang={&lang} />
                            }
                        }).collect::<Vec<_>>()
                    }
                </ul>
                {
                    replies.next_page.map(|next_page| {
                        render::rsx! {
                            <a href={format!("/posts/{}?page={}", post_id, next_page)}>{"-> "}{lang.tr("view_more_comments", None)}</a>
                        }
                    })
                }
            </div>
        </HTPage>
    }))


@@ 536,6 595,7 @@ async fn handler_post_submit_reply(
            return page_post_inner(
                post_id,
                &req_parts.headers,
                None,
                &cookies,
                ctx,
                Some(error),


@@ 565,6 625,7 @@ async fn handler_post_submit_reply(
            page_post_inner(
                post_id,
                &req_parts.headers,
                None,
                &cookies,
                ctx,
                Some(message),