mirror of
https://mzte.de/git/LordMZTE/brevo
synced 2024-05-16 14:03:45 +02:00
143 lines
3.6 KiB
Rust
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 {}
|