feat: comment on gists

master
Aravinth Manivannan 2 years ago
parent 95efab95da
commit dbc233c1ed
Signed by: realaravinth
GPG Key ID: AD9F0F08E855ED88

@ -1,4 +1,3 @@
use actix_http::header;
/*
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
*
@ -15,14 +14,17 @@ use actix_http::header;
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use actix_http::header;
use actix_web::http::StatusCode;
use actix_web::test;
use actix_web::ResponseError;
use db_core::prelude::*;
use pages::routes::PostCommentPath;
use super::new::*;
use crate::api::v1::gists::PostCommentRequest;
use crate::data::Data;
use crate::errors::*;
use crate::tests::*;
@ -44,6 +46,7 @@ async fn gists_new_route_works(data: Arc<Data>, db: BoxDB) {
const NAME: &str = "newgisttestuserexists";
const PASSWORD: &str = "longpassword2";
const EMAIL: &str = "newgisttestuserexists@a.com2";
const COMMENT: &str = "this string is never used anywhere but for commenting, so that I can get away with body inlcudes";
let db = &db;
let _ = data.delete_user(db, NAME, PASSWORD).await;
@ -95,9 +98,36 @@ async fn gists_new_route_works(data: Arc<Data>, db: BoxDB) {
let empty_gist = test::call_service(
&app,
post_request!(&serde_json::Value::default(), PAGES.gist.new, FORM)
.cookie(cookies)
.cookie(cookies.clone())
.to_request(),
)
.await;
assert_eq!(empty_gist.status(), ServiceError::GistEmpty.status_code());
// get gist
let mut route_iter = gist_id.to_str().unwrap().split('/');
let name = route_iter.nth(1).unwrap();
let gist = route_iter.next().unwrap();
let gist_route_componenet = PostCommentPath {
username: name.to_string(),
gist: gist.to_string(),
};
let gist_html_route = PAGES.gist.get_gist_route(&gist_route_componenet);
let gist_html_page = get_request!(&app, &gist_html_route);
assert_eq!(gist_html_page.status(), StatusCode::OK);
// post comment
let comment_url = PAGES.gist.get_post_comment_route(&gist_route_componenet);
let comment = PostCommentRequest {
comment: COMMENT.into(),
};
let comment_resp = test::call_service(
&app,
post_request!(&comment, &comment_url, FORM)
.cookie(cookies)
.to_request(),
)
.await;
assert_eq!(comment_resp.status(), StatusCode::FOUND);
}

@ -23,6 +23,7 @@ use tera::Context;
use db_core::prelude::*;
use crate::api::v1::gists::PostCommentRequest;
use crate::data::api::v1::gists::{GistID, GistInfo};
use crate::data::api::v1::render_html::GenerateHTML;
use crate::errors::*;
@ -50,8 +51,10 @@ pub fn register_templates(t: &mut tera::Tera) {
pub fn services(cfg: &mut web::ServiceConfig) {
cfg.service(view_preview);
cfg.service(post_comment);
}
#[derive(Clone)]
pub struct ViewGist {
ctx: RefCell<Context>,
}
@ -84,6 +87,14 @@ impl ViewGist {
username: &gist.owner,
}),
);
ctx.insert(
"gist_comment_link",
&PAGES.gist.get_post_comment_route(&PostCommentPath {
username: gist.owner.clone(),
gist: gist.id.clone(),
}),
);
}
if let Some(comments) = payload.comments {
@ -100,18 +111,19 @@ impl ViewGist {
.unwrap()
}
pub fn page(username: Option<&str>, payload: Payload, s: &Settings) -> String {
let p = Self::new(username, payload, s);
p.render()
pub fn set_comment(&self, comment: &PostCommentRequest) {
self.ctx
.borrow_mut()
.insert("new_comment", &comment.comment);
}
}
#[my_codegen::get(path = "PAGES.gist.view_gist", wrap = "super::get_auth_middleware()")]
async fn view_preview(
data: AppData,
db: crate::DB,
id: Identity,
path: web::Path<PostCommentPath>,
) -> PageResult<impl Responder, ViewGist> {
async fn view_util(
data: &AppData,
db: &crate::DB,
id: &Identity,
path: &web::Path<PostCommentPath>,
) -> PageResult<ViewGist, ViewGist> {
let username = id.identity();
let map_err = |e: ServiceError, gist: Option<&GistInfo>| -> PageError<ViewGist> {
@ -160,7 +172,76 @@ async fn view_preview(
comments: Some(&comments),
};
let page = ViewGist::page(username.as_deref(), ctx, &data.settings);
Ok(ViewGist::new(username.as_deref(), ctx, &data.settings))
}
#[my_codegen::get(path = "PAGES.gist.view_gist")]
async fn view_preview(
data: AppData,
db: crate::DB,
id: Identity,
path: web::Path<PostCommentPath>,
) -> PageResult<impl Responder, ViewGist> {
let page = view_util(&data, &db, &id, &path).await?.render();
let html = ContentType::html();
Ok(HttpResponse::Ok().content_type(html).body(page))
}
#[my_codegen::post(
path = "PAGES.gist.post_comment",
wrap = "super::get_auth_middleware()"
)]
async fn post_comment(
data: AppData,
db: crate::DB,
id: Identity,
payload: web::Form<PostCommentRequest>,
path: web::Path<PostCommentPath>,
) -> PageResult<impl Responder, ViewGist> {
let comment = payload.comment.trim();
let username = id.identity();
let page = view_util(&data, &db, &id, &path).await?;
let map_err = |e: ServiceError| -> PageError<ViewGist> {
let page = page.clone();
page.set_comment(&payload);
PageError::new(page, e)
};
let username = username.unwrap();
if comment.is_empty() {
return Err(map_err(ServiceError::EmptyComment));
}
let gist = db.get_gist(&path.gist).await.map_err(|e| {
let e: ServiceError = e.into();
map_err(e)
})?;
if gist.visibility == GistVisibility::Private && username != gist.owner {
return Err(map_err(ServiceError::GistNotFound));
}
let msg = CreateGistComment {
owner: &username,
gist_public_id: &path.gist,
comment: &payload.comment,
};
let _comment_id = db.new_comment(&msg).await.map_err(|e| {
let e: ServiceError = e.into();
map_err(e)
})?;
let gist_link = PostCommentPath {
username: gist.owner,
gist: gist.public_id,
};
let gist_link = PAGES.gist.get_gist_route(&gist_link);
Ok(HttpResponse::Found()
.insert_header((http::header::LOCATION, gist_link.as_str()))
.finish())
}

@ -85,6 +85,8 @@ pub struct Gists {
pub new: &'static str,
/// view gist
pub view_gist: &'static str,
/// post comment on gist
pub post_comment: &'static str,
}
impl Gists {
@ -92,11 +94,13 @@ impl Gists {
pub const fn new() -> Self {
let profile = "/{username}";
let view_gist = "/{username}/{gist}";
let post_comment = "/{username}/{gist}/comment";
let new = "/";
Self {
profile,
new,
view_gist,
post_comment,
}
}
@ -111,6 +115,13 @@ impl Gists {
.replace("{username}", &components.username)
.replace("{gist}", &components.gist)
}
/// get post_comment route with placeholders replaced with values provided.
pub fn get_post_comment_route(&self, components: &PostCommentPath) -> String {
self.post_comment
.replace("{username}", &components.username)
.replace("{gist}", &components.gist)
}
}
pub fn get_auth_middleware() -> Authentication<Pages> {
@ -140,6 +151,7 @@ mod tests {
const GIST: &str = "foo";
let get_profile = format!("/{NAME}");
let view_gist = format!("/{NAME}/{GIST}");
let post_comment = format!("/{NAME}/{GIST}/comment");
let profile_component = GistProfilePathComponent { username: NAME };
@ -151,5 +163,15 @@ mod tests {
};
assert_eq!(view_gist, PAGES.gist.get_gist_route(&profile_component));
let post_comment_path = PostCommentPath {
gist: GIST.into(),
username: NAME.into(),
};
assert_eq!(
post_comment,
PAGES.gist.get_post_comment_route(&post_comment_path)
);
}
}

@ -1,5 +1,5 @@
<div class="gist__comment-container">
<form action="" class="gist__comment-form" method="post" accept-charset="utf-8">
<form action="{{gist_comment_link}}" class="gist__comment-form" method="post" accept-charset="utf-8">
<label class="form__label" for="comment" >
<textarea
required

Loading…
Cancel
Save