uberbot/src/web_service.rs

144 lines
4.6 KiB
Rust
Raw Normal View History

2022-01-27 17:44:50 -06:00
use crate::database::Quote;
2022-01-05 17:23:00 -06:00
use crate::ExecutorConnection;
2022-01-26 12:16:54 -06:00
use irc::client::Client;
2022-01-27 17:44:50 -06:00
use lazy_static::lazy_static;
2022-01-26 12:16:54 -06:00
use reqwest::StatusCode;
2022-01-27 17:44:50 -06:00
use serde::{Deserialize, Serialize};
2022-01-26 05:58:49 -06:00
use serde_json::Value::Null;
2022-01-13 10:52:39 -06:00
use std::net::SocketAddr;
2022-01-26 12:16:54 -06:00
use std::sync::Arc;
use tera::{Context, Tera};
2022-01-26 12:16:54 -06:00
use tokio::sync::broadcast::Receiver;
use warp::{reply, Filter, Reply};
2022-01-26 17:58:00 -06:00
lazy_static! {
static ref TERA: Tera = Tera::new("templates/**/*").unwrap();
2022-01-26 17:58:00 -06:00
}
2022-01-05 17:23:00 -06:00
pub async fn run(
db: ExecutorConnection,
2022-01-26 12:16:54 -06:00
wh_irc: Arc<Client>,
wh_channel: String,
listen: SocketAddr,
2022-01-27 17:44:50 -06:00
mut cancel: Receiver<()>,
2022-01-26 12:16:54 -06:00
) {
2022-01-27 17:44:50 -06:00
let quote_get = warp::get()
.and(warp::path("quotes"))
.and(warp::query::<QuotesQuery>())
.and(warp::any().map(move || db.clone()))
2022-01-27 17:44:50 -06:00
.then(handle_get_quote);
2022-01-05 17:23:00 -06:00
let webhook_post = warp::path("webhook")
.and(warp::post())
.and(warp::body::json())
2022-01-26 12:16:54 -06:00
.and(warp::any().map(move || wh_irc.clone()))
.and(warp::any().map(move || wh_channel.clone()))
.map(handle_webhook);
2022-01-05 17:23:00 -06:00
2022-01-27 17:44:50 -06:00
let routes = webhook_post.or(quote_get);
warp::serve(routes)
.bind_with_graceful_shutdown(listen, async move {
let _ = cancel.recv().await;
})
.1
.await;
tracing::info!("Web service finished");
2022-01-05 17:23:00 -06:00
}
2022-01-26 17:58:00 -06:00
#[derive(Serialize)]
struct QuotesTemplate {
2022-01-27 17:44:50 -06:00
quotes: Option<Vec<Quote>>,
flash: Option<String>,
}
#[derive(Deserialize)]
struct QuotesQuery {
q: Option<String>,
2022-01-26 17:58:00 -06:00
}
2022-01-27 17:44:50 -06:00
async fn handle_get_quote(query: QuotesQuery, db: ExecutorConnection) -> impl Reply {
2022-01-30 11:26:09 -06:00
let template = if let Some(q) = query.q {
if let Some(quotes) = db.search(q.clone()).await {
2022-01-27 17:44:50 -06:00
let quotes_count = quotes.len();
QuotesTemplate {
quotes: Some(quotes),
2022-01-30 11:26:09 -06:00
flash: Some(format!(
"Displaying {}/50 results for query \"{}\"",
quotes_count, q
)),
2022-01-27 17:44:50 -06:00
}
} else {
QuotesTemplate {
quotes: None,
flash: Some("A database error has occurred".into()),
}
}
} else {
QuotesTemplate {
2022-01-30 11:26:09 -06:00
quotes: db.random20().await,
flash: Some("Displaying up to 20 random quotes".into()),
2022-01-27 17:44:50 -06:00
}
};
match TERA.render("quotes.html", &Context::from_serialize(&template).unwrap()) {
2022-01-26 17:58:00 -06:00
Ok(o) => reply::html(o).into_response(),
Err(e) => {
tracing::warn!("Error while rendering template: {}", e);
2022-01-27 17:44:50 -06:00
reply::with_status(
"Failed to render template",
StatusCode::INTERNAL_SERVER_ERROR,
)
.into_response()
2022-01-26 17:58:00 -06:00
}
}
2022-01-05 17:23:00 -06:00
}
2022-01-26 05:58:49 -06:00
#[allow(clippy::needless_pass_by_value)]
fn handle_webhook(json: serde_json::Value, irc: Arc<Client>, channel: String) -> impl Reply {
2022-01-26 05:58:49 -06:00
if json["commits"] != Null {
let commits = json["commits"].as_array().unwrap();
let repo = &json["repository"]["full_name"].as_str().unwrap().trim();
if commits.len() == 1 {
let author = &json["commits"][0]["author"]["name"]
.as_str()
.unwrap()
.trim();
let message = &json["commits"][0]["message"].as_str().unwrap().trim();
if let Err(e) = irc.send_privmsg(
channel,
format!("New commit on {}: {} - {}", repo, message, author),
) {
return reply::with_status(
format!("An error has occurred: {}", e),
StatusCode::INTERNAL_SERVER_ERROR,
)
.into_response();
}
} else {
2022-01-26 12:16:54 -06:00
if let Err(e) = irc.send_privmsg(
channel.clone(),
format!("{} new commits on {}:", commits.len(), repo),
) {
return reply::with_status(
format!("An error has occurred: {}", e),
StatusCode::INTERNAL_SERVER_ERROR,
)
.into_response();
}
2022-01-26 05:58:49 -06:00
for commit in commits {
let author = &commit["author"]["name"].as_str().unwrap().trim();
let message = &commit["message"].as_str().unwrap().trim();
2022-01-26 12:16:54 -06:00
if let Err(e) =
irc.send_privmsg(channel.clone(), format!("{} - {}", author, message))
{
return reply::with_status(
format!("An error has occurred: {}", e),
StatusCode::INTERNAL_SERVER_ERROR,
)
.into_response();
}
2022-01-26 05:58:49 -06:00
}
}
}
2022-01-26 12:16:54 -06:00
StatusCode::CREATED.into_response()
2022-01-26 05:58:49 -06:00
}