727 lines
19 KiB
Rust
727 lines
19 KiB
Rust
|
#![allow(clippy::too_many_arguments)]
|
||
|
|
||
|
pub mod queries;
|
||
|
pub mod templates;
|
||
|
|
||
|
use super::{check_admin_password, check_admin_password_hash};
|
||
|
use crate::{config::*, db::*, helpers, locales::*, notify::Notification};
|
||
|
use queries::*;
|
||
|
use templates::*;
|
||
|
|
||
|
use crossbeam_channel::Sender;
|
||
|
use fluent_bundle::FluentArgs;
|
||
|
use log::{error, warn};
|
||
|
use tera::Context;
|
||
|
use unic_langid::LanguageIdentifier;
|
||
|
|
||
|
pub async fn init_routes(
|
||
|
app: &mut tide::Server<()>,
|
||
|
config: &'static Config,
|
||
|
dbs: Dbs,
|
||
|
templates: &'static Templates,
|
||
|
locales: &'static Locales,
|
||
|
notify_send: Sender<Notification>,
|
||
|
) {
|
||
|
app.at(&format!("{}t/:topic", config.root_url)).get({
|
||
|
let dbs = dbs.clone();
|
||
|
move |req: tide::Request<()>| {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_comments(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs.clone(),
|
||
|
client_langs,
|
||
|
Context::new(),
|
||
|
200,
|
||
|
)
|
||
|
}
|
||
|
});
|
||
|
app.at(&format!("{}t/:topic", config.root_url)).post({
|
||
|
let dbs = dbs.clone();
|
||
|
let notify_send = notify_send.clone();
|
||
|
move |req: tide::Request<()>| {
|
||
|
handle_post_comments(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs.clone(),
|
||
|
locales,
|
||
|
notify_send.clone(),
|
||
|
)
|
||
|
}
|
||
|
});
|
||
|
app.at(&format!(
|
||
|
"{}t/:topic/edit/:comment_id/:mutation_token",
|
||
|
config.root_url
|
||
|
))
|
||
|
.get({
|
||
|
let dbs = dbs.clone();
|
||
|
move |req: tide::Request<()>| {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_edit_comment(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs.clone(),
|
||
|
client_langs,
|
||
|
Context::new(),
|
||
|
200,
|
||
|
)
|
||
|
}
|
||
|
});
|
||
|
app.at(&format!(
|
||
|
"{}t/:topic/edit/:comment_id/:mutation_token",
|
||
|
config.root_url
|
||
|
))
|
||
|
.post({
|
||
|
let dbs = dbs.clone();
|
||
|
move |req: tide::Request<()>| {
|
||
|
handle_post_comments(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs.clone(),
|
||
|
locales,
|
||
|
notify_send.clone(),
|
||
|
)
|
||
|
}
|
||
|
});
|
||
|
app.at(&format!("{}admin", config.root_url))
|
||
|
.get(move |req: tide::Request<()>| {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin_login(req, config, templates, client_langs)
|
||
|
});
|
||
|
app.at(&format!("{}admin", config.root_url)).post({
|
||
|
move |req: tide::Request<()>| handle_post_admin(req, config, templates, dbs.clone())
|
||
|
});
|
||
|
}
|
||
|
|
||
|
async fn serve_edit_comment<'a>(
|
||
|
req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
dbs: Dbs,
|
||
|
client_langs: Vec<LanguageIdentifier>,
|
||
|
mut context: Context,
|
||
|
status_code: u16,
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
let (Ok(comment_id_str), Ok(mutation_token_str)) = (req.param("comment_id"), req.param("mutation_token")) else {
|
||
|
context.insert("log", &["no comment id or no token"]);
|
||
|
return serve_comments(req, config, templates, dbs, client_langs, context, 400).await;
|
||
|
};
|
||
|
|
||
|
let (Ok(comment_id), Ok(mutation_token)) = (CommentId::from_base64(comment_id_str), MutationToken::from_base64(mutation_token_str)) else {
|
||
|
context.insert("log", &["badly encoded comment id or token"]);
|
||
|
return serve_comments(req, config, templates, dbs, client_langs, context, 400).await;
|
||
|
};
|
||
|
|
||
|
let Some((comment, _edited_comment)) = dbs.comment.get(&comment_id).unwrap() else {
|
||
|
context.insert("log", &["not found comment"]);
|
||
|
return serve_comments(req, config, templates, dbs, client_langs, context, 404).await;
|
||
|
};
|
||
|
|
||
|
if let Err(e) = helpers::check_can_edit_comment(config, &comment, &mutation_token) {
|
||
|
context.insert("log", &[e]);
|
||
|
return serve_comments(req, config, templates, dbs, client_langs, context, 403).await;
|
||
|
}
|
||
|
|
||
|
context.insert("edit_comment", &comment_id.to_base64());
|
||
|
context.insert("edit_comment_mutation_token", &mutation_token.to_base64());
|
||
|
context.insert("edit_comment_author", &comment.author);
|
||
|
context.insert("edit_comment_email", &comment.email);
|
||
|
context.insert("edit_comment_text", &comment.text);
|
||
|
|
||
|
serve_comments(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs,
|
||
|
client_langs,
|
||
|
context,
|
||
|
status_code,
|
||
|
)
|
||
|
.await
|
||
|
}
|
||
|
|
||
|
async fn serve_comments<'a>(
|
||
|
req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
dbs: Dbs,
|
||
|
client_langs: Vec<LanguageIdentifier>,
|
||
|
mut context: Context,
|
||
|
status_code: u16,
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
let Ok(topic) = req.param("topic") else {
|
||
|
return Err(tide::Error::from_str(404, "No topic"))
|
||
|
};
|
||
|
|
||
|
let admin = req.cookie("admin").map_or(false, |psw| {
|
||
|
check_admin_password_hash(config, &String::from(psw.value()))
|
||
|
});
|
||
|
|
||
|
let topic_hash = TopicHash::from_topic(topic);
|
||
|
|
||
|
context.insert("config", &config);
|
||
|
context.insert("admin", &admin);
|
||
|
let time_lang = get_time_lang(&client_langs);
|
||
|
context.insert(
|
||
|
"time_lang",
|
||
|
time_lang.as_ref().unwrap_or(&config.default_lang),
|
||
|
);
|
||
|
context.insert(
|
||
|
"l",
|
||
|
&client_langs
|
||
|
.iter()
|
||
|
.map(|lang| lang.language.as_str())
|
||
|
.collect::<Vec<&str>>(),
|
||
|
);
|
||
|
|
||
|
if admin {
|
||
|
if let Ok(query) = req.query::<ApproveQuery>() {
|
||
|
if let Ok(comment_id) = CommentId::from_base64(&query.approve) {
|
||
|
helpers::approve_comment(comment_id, &dbs)
|
||
|
.map_err(|e| error!("Approving comment: {:?}", e))
|
||
|
.ok();
|
||
|
}
|
||
|
}
|
||
|
if let Ok(query) = req.query::<ApproveEditQuery>() {
|
||
|
if let Ok(comment_id) = CommentId::from_base64(&query.approve_edit) {
|
||
|
helpers::approve_edit(comment_id, &dbs)
|
||
|
.map_err(|e| error!("Approving edit: {:?}", e))
|
||
|
.ok();
|
||
|
}
|
||
|
}
|
||
|
if let Ok(query) = req.query::<RemoveQuery>() {
|
||
|
if let Ok(comment_id) = CommentId::from_base64(&query.remove) {
|
||
|
helpers::remove_comment(comment_id, &dbs)
|
||
|
.map_err(|e| error!("Removing comment: {:?}", e))
|
||
|
.ok();
|
||
|
}
|
||
|
}
|
||
|
if let Ok(query) = req.query::<RemoveEditQuery>() {
|
||
|
if let Ok(comment_id) = CommentId::from_base64(&query.remove_edit) {
|
||
|
helpers::remove_edit(comment_id, &dbs)
|
||
|
.map_err(|e| error!("Removing edit: {:?}", e))
|
||
|
.ok();
|
||
|
}
|
||
|
}
|
||
|
if let Ok(query) = req.query::<EditQuery>() {
|
||
|
if let Ok(comment_id) = CommentId::from_base64(&query.edit) {
|
||
|
if let Some((comment, _comment_status)) = dbs.comment.get(&comment_id).unwrap() {
|
||
|
context.insert("edit_comment", &comment_id.to_base64());
|
||
|
context.insert("edit_comment_author", &comment.author);
|
||
|
context.insert("edit_comment_email", &comment.email);
|
||
|
context.insert("edit_comment_text", &comment.text);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
context.insert(
|
||
|
"comments_pending",
|
||
|
&helpers::iter_pending_comments_by_topic(topic_hash.clone(), &dbs)
|
||
|
.map(|(comment_id, comment, addr, comment_status)| {
|
||
|
if let CommentStatus::ApprovedEdited(edited_comment) = comment_status {
|
||
|
CommentWithId {
|
||
|
addr: addr.map(|addr| addr.to_string()),
|
||
|
author: edited_comment.author,
|
||
|
editable: true,
|
||
|
id: comment_id.to_base64(),
|
||
|
last_edit_time: edited_comment.last_edit_time,
|
||
|
needs_approval: true,
|
||
|
original: Some(OriginalComment {
|
||
|
author: comment.author,
|
||
|
editable: true,
|
||
|
last_edit_time: comment.last_edit_time,
|
||
|
post_time: comment.post_time,
|
||
|
text: comment.text,
|
||
|
}),
|
||
|
post_time: edited_comment.post_time,
|
||
|
text: edited_comment.text,
|
||
|
}
|
||
|
} else {
|
||
|
CommentWithId {
|
||
|
addr: addr.map(|addr| addr.to_string()),
|
||
|
author: comment.author,
|
||
|
editable: true,
|
||
|
id: comment_id.to_base64(),
|
||
|
last_edit_time: comment.last_edit_time,
|
||
|
needs_approval: true,
|
||
|
original: None,
|
||
|
post_time: comment.post_time,
|
||
|
text: comment.text,
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
.collect::<Vec<CommentWithId>>(),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
context.insert(
|
||
|
"comments",
|
||
|
&helpers::iter_approved_comments_by_topic(topic_hash, &dbs)
|
||
|
.map(|(comment_id, comment, _comment_status)| CommentWithId {
|
||
|
addr: None,
|
||
|
author: comment.author,
|
||
|
editable: admin,
|
||
|
id: comment_id.to_base64(),
|
||
|
last_edit_time: comment.last_edit_time,
|
||
|
needs_approval: false,
|
||
|
original: None,
|
||
|
post_time: comment.post_time,
|
||
|
text: comment.text,
|
||
|
})
|
||
|
.collect::<Vec<CommentWithId>>(),
|
||
|
);
|
||
|
|
||
|
Ok(tide::Response::builder(status_code)
|
||
|
.content_type(tide::http::mime::HTML)
|
||
|
.body(templates.tera.render("comments.html", &context)?)
|
||
|
.build())
|
||
|
}
|
||
|
|
||
|
async fn serve_admin<'a>(
|
||
|
_req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
dbs: Dbs,
|
||
|
client_langs: &[LanguageIdentifier],
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
let mut context = Context::new();
|
||
|
context.insert("config", &config);
|
||
|
context.insert("admin", &true);
|
||
|
let time_lang = get_time_lang(client_langs);
|
||
|
context.insert(
|
||
|
"time_lang",
|
||
|
time_lang.as_ref().unwrap_or(&config.default_lang),
|
||
|
);
|
||
|
context.insert(
|
||
|
"l",
|
||
|
&client_langs
|
||
|
.iter()
|
||
|
.map(|lang| lang.language.as_str())
|
||
|
.collect::<Vec<&str>>(),
|
||
|
);
|
||
|
|
||
|
context.insert(
|
||
|
"comments",
|
||
|
&dbs.comment_pending
|
||
|
.iter()
|
||
|
.filter_map(|entry| {
|
||
|
let ((_topic_hash, _time, comment_id), (addr, _is_edit)) = entry
|
||
|
.map_err(|e| error!("Reading comment_pending: {:?}", e))
|
||
|
.ok()?;
|
||
|
let (comment, comment_status) = dbs
|
||
|
.comment
|
||
|
.get(&comment_id)
|
||
|
.map_err(|e| error!("Reading comment: {:?}", e))
|
||
|
.ok()?
|
||
|
.or_else(|| {
|
||
|
error!("Comment not found");
|
||
|
None
|
||
|
})?;
|
||
|
if let CommentStatus::ApprovedEdited(edited_comment) = comment_status {
|
||
|
Some(CommentWithId {
|
||
|
addr: addr.map(|addr| addr.to_string()),
|
||
|
author: edited_comment.author,
|
||
|
editable: true,
|
||
|
id: comment_id.to_base64(),
|
||
|
last_edit_time: edited_comment.last_edit_time,
|
||
|
needs_approval: true,
|
||
|
original: Some(OriginalComment {
|
||
|
author: comment.author,
|
||
|
editable: true,
|
||
|
last_edit_time: comment.last_edit_time,
|
||
|
post_time: comment.post_time,
|
||
|
text: comment.text,
|
||
|
}),
|
||
|
post_time: edited_comment.post_time,
|
||
|
text: edited_comment.text,
|
||
|
})
|
||
|
} else {
|
||
|
Some(CommentWithId {
|
||
|
addr: addr.map(|addr| addr.to_string()),
|
||
|
author: comment.author,
|
||
|
editable: true,
|
||
|
id: comment_id.to_base64(),
|
||
|
last_edit_time: comment.last_edit_time,
|
||
|
needs_approval: true,
|
||
|
original: None,
|
||
|
post_time: comment.post_time,
|
||
|
text: comment.text,
|
||
|
})
|
||
|
}
|
||
|
})
|
||
|
.collect::<Vec<CommentWithId>>(),
|
||
|
);
|
||
|
|
||
|
Ok(tide::Response::builder(200)
|
||
|
.content_type(tide::http::mime::HTML)
|
||
|
.body(templates.tera.render("comments.html", &context)?)
|
||
|
.build())
|
||
|
}
|
||
|
|
||
|
async fn serve_admin_login(
|
||
|
_req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
client_langs: Vec<LanguageIdentifier>,
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
let mut context = Context::new();
|
||
|
context.insert("config", &config);
|
||
|
let time_lang = get_time_lang(&client_langs);
|
||
|
context.insert(
|
||
|
"time_lang",
|
||
|
time_lang.as_ref().unwrap_or(&config.default_lang),
|
||
|
);
|
||
|
context.insert(
|
||
|
"l",
|
||
|
&client_langs
|
||
|
.iter()
|
||
|
.map(|lang| lang.language.as_str())
|
||
|
.collect::<Vec<&str>>(),
|
||
|
);
|
||
|
|
||
|
Ok(tide::Response::builder(200)
|
||
|
.content_type(tide::http::mime::HTML)
|
||
|
.body(templates.tera.render("admin_login.html", &context)?)
|
||
|
.build())
|
||
|
}
|
||
|
|
||
|
async fn handle_post_comments(
|
||
|
mut req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
dbs: Dbs,
|
||
|
locales: &Locales,
|
||
|
notify_send: Sender<Notification>,
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
let admin = req.cookie("admin").map_or(false, |psw| {
|
||
|
check_admin_password_hash(config, &String::from(psw.value()))
|
||
|
});
|
||
|
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
|
||
|
let client_addr = match helpers::get_client_addr(config, &req) {
|
||
|
Some(Ok(addr)) => Some(addr),
|
||
|
Some(Err(e)) => {
|
||
|
warn!("Unable to parse client addr: {}", e);
|
||
|
None
|
||
|
}
|
||
|
None => {
|
||
|
warn!("No client addr");
|
||
|
None
|
||
|
}
|
||
|
};
|
||
|
let antispam_enabled = !admin
|
||
|
&& config.antispam_enable
|
||
|
&& client_addr
|
||
|
.as_ref()
|
||
|
.map_or(false, |addr| !config.antispam_whitelist.contains(addr));
|
||
|
|
||
|
let mut errors = Vec::new();
|
||
|
let mut context = Context::new();
|
||
|
|
||
|
match req.body_form::<CommentQuery>().await? {
|
||
|
CommentQuery::NewComment(query) => {
|
||
|
let Ok(topic) = req.param("topic") else {
|
||
|
return Err(tide::Error::from_str(404, "No topic"))
|
||
|
};
|
||
|
|
||
|
helpers::check_comment(config, locales, &client_langs, &query.comment, &mut errors);
|
||
|
|
||
|
if let Some(client_addr) = &client_addr {
|
||
|
if antispam_enabled {
|
||
|
if let Some(antispam_timeout) =
|
||
|
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap()
|
||
|
{
|
||
|
errors.push(
|
||
|
locales
|
||
|
.tr(
|
||
|
&client_langs,
|
||
|
"error-antispam",
|
||
|
Some(&FluentArgs::from_iter([(
|
||
|
"antispam_timeout",
|
||
|
antispam_timeout,
|
||
|
)])),
|
||
|
)
|
||
|
.unwrap()
|
||
|
.into_owned(),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if errors.is_empty() {
|
||
|
if let Some(client_addr) = &client_addr {
|
||
|
if antispam_enabled {
|
||
|
helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let topic_hash = TopicHash::from_topic(topic);
|
||
|
|
||
|
let time = std::time::SystemTime::now()
|
||
|
.duration_since(std::time::UNIX_EPOCH)
|
||
|
.unwrap()
|
||
|
.as_secs();
|
||
|
|
||
|
let comment = Comment {
|
||
|
topic_hash,
|
||
|
author: if query.comment.author.is_empty() {
|
||
|
petname::Petnames::large().generate_one(2, " ")
|
||
|
} else {
|
||
|
query.comment.author
|
||
|
},
|
||
|
email: if query.comment.email.is_empty() {
|
||
|
None
|
||
|
} else {
|
||
|
Some(query.comment.email)
|
||
|
},
|
||
|
last_edit_time: None,
|
||
|
mutation_token: MutationToken::new(),
|
||
|
post_time: time,
|
||
|
text: query.comment.text,
|
||
|
};
|
||
|
match helpers::new_pending_comment(&comment, client_addr, &dbs) {
|
||
|
Ok(comment_id) => {
|
||
|
notify_send
|
||
|
.send(Notification {
|
||
|
topic: topic.to_string(),
|
||
|
})
|
||
|
.ok();
|
||
|
context.insert(
|
||
|
"log",
|
||
|
&[locales
|
||
|
.tr(
|
||
|
&client_langs,
|
||
|
if config.comment_approve {
|
||
|
"new_comment-success_pending"
|
||
|
} else {
|
||
|
"new_comment-success"
|
||
|
},
|
||
|
Some(&FluentArgs::from_iter([(
|
||
|
"edit_link",
|
||
|
format!(
|
||
|
"{}t/{}/edit/{}/{}",
|
||
|
&config.root_url,
|
||
|
topic,
|
||
|
comment_id.to_base64(),
|
||
|
comment.mutation_token.to_base64(),
|
||
|
),
|
||
|
)])),
|
||
|
)
|
||
|
.unwrap()],
|
||
|
);
|
||
|
}
|
||
|
// TODO add message to client log and change http code
|
||
|
Err(e) => error!("Adding pending comment: {:?}", e),
|
||
|
}
|
||
|
} else {
|
||
|
context.insert("new_comment_author", &query.comment.author);
|
||
|
context.insert("new_comment_email", &query.comment.email);
|
||
|
context.insert("new_comment_text", &query.comment.text);
|
||
|
}
|
||
|
context.insert("new_comment_errors", &errors);
|
||
|
}
|
||
|
CommentQuery::EditComment(query) => {
|
||
|
let Ok(topic) = req.param("topic") else {
|
||
|
return Err(tide::Error::from_str(404, "No topic"))
|
||
|
};
|
||
|
|
||
|
let Ok(comment_id) = CommentId::from_base64(&query.id) else {
|
||
|
return Err(tide::Error::from_str(400, "Invalid comment id"));
|
||
|
};
|
||
|
|
||
|
let Some((old_comment, old_edited_comment)) = dbs.comment.get(&comment_id).unwrap() else {
|
||
|
return Err(tide::Error::from_str(404, "Not found"));
|
||
|
};
|
||
|
|
||
|
helpers::check_comment(config, locales, &client_langs, &query.comment, &mut errors);
|
||
|
|
||
|
let mutation_token = if admin {
|
||
|
None
|
||
|
} else {
|
||
|
'mutation_token: {
|
||
|
let Ok(mutation_token_str) = req.param("mutation_token") else {
|
||
|
errors.push("no mutation token".into());
|
||
|
break 'mutation_token None;
|
||
|
};
|
||
|
|
||
|
let Ok(mutation_token) = MutationToken::from_base64(mutation_token_str) else {
|
||
|
errors.push("badly encoded token".into());
|
||
|
break 'mutation_token None;
|
||
|
};
|
||
|
|
||
|
if let Err(e) =
|
||
|
helpers::check_can_edit_comment(config, &old_comment, &mutation_token)
|
||
|
{
|
||
|
errors.push(e.to_string());
|
||
|
}
|
||
|
|
||
|
Some(mutation_token)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if !admin {
|
||
|
if let Some(client_addr) = &client_addr {
|
||
|
if let Some(antispam_timeout) =
|
||
|
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap()
|
||
|
{
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
errors.push(
|
||
|
locales
|
||
|
.tr(
|
||
|
&client_langs,
|
||
|
"error-antispam",
|
||
|
Some(&FluentArgs::from_iter([(
|
||
|
"antispam_timeout",
|
||
|
antispam_timeout,
|
||
|
)])),
|
||
|
)
|
||
|
.unwrap()
|
||
|
.into_owned(),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if errors.is_empty() {
|
||
|
if !admin {
|
||
|
if let Some(client_addr) = &client_addr {
|
||
|
helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
let time = std::time::SystemTime::now()
|
||
|
.duration_since(std::time::UNIX_EPOCH)
|
||
|
.unwrap()
|
||
|
.as_secs();
|
||
|
|
||
|
let mut comment = old_comment.clone();
|
||
|
|
||
|
comment.author = if query.comment.author.is_empty() {
|
||
|
petname::Petnames::large().generate_one(2, " ")
|
||
|
} else {
|
||
|
query.comment.author
|
||
|
};
|
||
|
comment.email = if query.comment.email.is_empty() {
|
||
|
None
|
||
|
} else {
|
||
|
Some(query.comment.email)
|
||
|
};
|
||
|
comment.text = query.comment.text;
|
||
|
comment.last_edit_time = Some(time);
|
||
|
|
||
|
match helpers::edit_comment(
|
||
|
comment_id.clone(),
|
||
|
old_comment,
|
||
|
old_edited_comment,
|
||
|
comment.clone(),
|
||
|
client_addr,
|
||
|
&dbs,
|
||
|
) {
|
||
|
Ok(()) => {
|
||
|
context.insert(
|
||
|
"log",
|
||
|
&[locales
|
||
|
.tr(
|
||
|
&client_langs,
|
||
|
if config.comment_approve {
|
||
|
"edit_comment-success_pending"
|
||
|
} else {
|
||
|
"edit_comment-success"
|
||
|
},
|
||
|
Some(&FluentArgs::from_iter([(
|
||
|
"edit_link",
|
||
|
format!(
|
||
|
"{}t/{}/edit/{}/{}",
|
||
|
&config.root_url,
|
||
|
topic,
|
||
|
comment_id.to_base64(),
|
||
|
comment.mutation_token.to_base64(),
|
||
|
),
|
||
|
)])),
|
||
|
)
|
||
|
.unwrap()],
|
||
|
);
|
||
|
}
|
||
|
// TODO add message to client log and change http code
|
||
|
Err(e) => error!("Editing comment: {:?}", e),
|
||
|
}
|
||
|
} else {
|
||
|
context.insert("edit_comment", &comment_id.to_base64());
|
||
|
if let Some(mutation_token) = &mutation_token {
|
||
|
context.insert("edit_comment_mutation_token", &mutation_token.to_base64());
|
||
|
}
|
||
|
context.insert("edit_comment_author", &query.comment.author);
|
||
|
context.insert("edit_comment_email", &query.comment.email);
|
||
|
context.insert("edit_comment_text", &query.comment.text);
|
||
|
context.insert("edit_comment_errors", &errors);
|
||
|
|
||
|
return serve_edit_comment(req, config, templates, dbs, client_langs, context, 400)
|
||
|
.await;
|
||
|
}
|
||
|
context.insert("edit_comment_errors", &errors);
|
||
|
}
|
||
|
}
|
||
|
serve_comments(
|
||
|
req,
|
||
|
config,
|
||
|
templates,
|
||
|
dbs,
|
||
|
client_langs,
|
||
|
context,
|
||
|
if errors.is_empty() { 200 } else { 400 },
|
||
|
)
|
||
|
.await
|
||
|
}
|
||
|
|
||
|
async fn handle_post_admin(
|
||
|
mut req: tide::Request<()>,
|
||
|
config: &Config,
|
||
|
templates: &Templates,
|
||
|
dbs: Dbs,
|
||
|
) -> tide::Result<tide::Response> {
|
||
|
if let Some(psw) = req.cookie("admin") {
|
||
|
if check_admin_password(config, &String::from(psw.value())).is_some() {
|
||
|
#[allow(clippy::match_single_binding)]
|
||
|
match req.body_form::<AdminQuery>().await? {
|
||
|
_ => {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin(req, config, templates, dbs, &client_langs).await
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin_login(req, config, templates, client_langs).await
|
||
|
}
|
||
|
} else if let AdminQuery::Login(query) = req.body_form::<AdminQuery>().await? {
|
||
|
if let Some(password_hash) = check_admin_password(config, &query.psw) {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin(req, config, templates, dbs, &client_langs)
|
||
|
.await
|
||
|
.map(|mut r| {
|
||
|
let mut cookie = tide::http::Cookie::new("admin", password_hash);
|
||
|
cookie.set_http_only(Some(true));
|
||
|
cookie.set_path(config.root_url.clone());
|
||
|
if let Some(domain) = &config.cookies_domain {
|
||
|
cookie.set_domain(domain.clone());
|
||
|
}
|
||
|
if config.cookies_https_only {
|
||
|
cookie.set_secure(Some(true));
|
||
|
}
|
||
|
r.insert_cookie(cookie);
|
||
|
r
|
||
|
})
|
||
|
} else {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin_login(req, config, templates, client_langs).await
|
||
|
}
|
||
|
} else {
|
||
|
let client_langs = get_client_langs(&req);
|
||
|
serve_admin_login(req, config, templates, client_langs).await
|
||
|
}
|
||
|
}
|