1
0
Fork 0
mirror of https://mzte.de/git/LordMZTE/brevo synced 2024-05-16 14:03:45 +02:00
brevo/src/handlers.rs
2021-06-24 15:57:11 +02:00

143 lines
3.6 KiB
Rust

use crate::util::gen_id;
use crate::util::make_link;
use crate::util::render_reject;
use serde::{Deserialize, Serialize};
use sqlx::Row;
use std::sync::Arc;
use tera::Context;
use url::Url;
use warp::http::uri::InvalidUri;
use warp::redirect;
use warp::{
http::Uri,
reject::{self, Reject},
reply, Rejection, Reply,
};
use crate::{sqlargs, util::sql_reject, Brevo};
pub async fn index(brevo: Arc<Brevo>) -> Result<Box<dyn Reply>, Rejection> {
let rendered = brevo.tera.render("index.html", &Context::new());
match rendered {
Err(_) => Err(reject::custom(BrevoReject::RenderFail)),
Ok(r) => Ok(Box::new(reply::html(r))),
}
}
pub async fn shortened(id: String, brevo: Arc<Brevo>) -> Result<Box<dyn Reply>, Rejection> {
make_table(Arc::clone(&brevo)).await?;
let url = sqlx::query_with(
"
SELECT url FROM urls
WHERE id = ?
",
sqlargs![&id],
)
.fetch_optional(&brevo.pool)
.await
.map_err(sql_reject)?;
match url {
Some(u) => Ok(Box::new(redirect::permanent(
u.try_get::<String, _>(0)
.map_err(sql_reject)?
.parse::<Uri>()
.map_err(|e| reject::custom(BrevoReject::UriParseError(e)))?,
))),
None => Err(reject::not_found()),
}
}
pub async fn submit(form_data: SubmitForm, brevo: Arc<Brevo>) -> Result<Box<dyn Reply>, Rejection> {
make_table(Arc::clone(&brevo)).await?;
let url = form_data.url.as_str();
let id = sqlx::query_with(
"
SELECT id FROM urls
WHERE url = ?
",
sqlargs![url],
)
.fetch_optional(&brevo.pool)
.await
.map_err(sql_reject)?;
if let Some(id) = id {
let id = id.try_get::<String, _>(0).map_err(sql_reject)?;
let rendered = brevo
.tera
.render(
"success.html",
&Context::from_serialize(SuccessContent {
link: make_link(Arc::clone(&brevo), &id)?,
})
.map_err(render_reject)?,
)
.map_err(render_reject)?;
Ok(Box::new(reply::html(rendered)))
} else {
let id = gen_id(Arc::clone(&brevo)).await;
sqlx::query_with(
"
INSERT INTO urls ( id, url ) VALUES
( ?, ? )
",
sqlargs![&id, url],
)
.execute(&brevo.pool)
.await
.map_err(sql_reject)?;
let rendered = brevo
.tera
.render(
"success.html",
&Context::from_serialize(SuccessContent {
link: make_link(Arc::clone(&brevo), &id)?,
})
.map_err(render_reject)?,
)
.map_err(render_reject)?;
Ok(Box::new(reply::html(rendered)))
}
}
async fn make_table(brevo: Arc<Brevo>) -> Result<(), Rejection> {
// can't parameterize VARCHAR len, but this should be safe
sqlx::query(&format!(
"
CREATE TABLE IF NOT EXISTS urls (
id VARCHAR({}) PRIMARY KEY,
url TEXT NOT NULL UNIQUE
)
",
brevo.config.link_len
))
.execute(&brevo.pool)
.await
.map_err(sql_reject)?;
Ok(())
}
#[derive(Serialize)]
struct SuccessContent {
link: String,
}
#[derive(Deserialize)]
pub struct SubmitForm {
url: Url,
}
// TODO: implement reject handerls
#[derive(Debug)]
pub enum BrevoReject {
RenderFail,
SqlError(sqlx::Error),
UrlParseError(url::ParseError),
UriParseError(InvalidUri),
}
impl Reject for BrevoReject {}