176 lines
5.4 KiB
Rust
176 lines
5.4 KiB
Rust
use actix_web::{get, http, web, HttpResponse};
|
|
use actix_web_static_files::ResourceFiles;
|
|
use askama_actix::TemplateToResponse;
|
|
use diesel::prelude::*;
|
|
use r2d2_redis::redis;
|
|
use std::ops::DerefMut;
|
|
|
|
use crate::{cache, config, db, markdown};
|
|
|
|
pub mod templates;
|
|
|
|
pub mod static_dir {
|
|
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
|
|
}
|
|
|
|
async fn not_found() -> HttpResponse {
|
|
let mut resp = templates::StatusCode {
|
|
status_code: http::StatusCode::NOT_FOUND,
|
|
message: Some("maybe try a correct url?".to_string()),
|
|
}
|
|
.to_response();
|
|
*resp.status_mut() = http::StatusCode::NOT_FOUND;
|
|
|
|
resp
|
|
}
|
|
|
|
#[get("/posts")]
|
|
async fn posts(db_pool: web::Data<db::DbPool>) -> HttpResponse {
|
|
let db_conn = &mut match db_pool.get() {
|
|
Ok(x) => x,
|
|
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
|
|
};
|
|
|
|
let posts = match db::schema::posts::table
|
|
.filter(db::schema::posts::active)
|
|
.order(db::schema::posts::published_at.desc())
|
|
.load::<db::models::Post>(db_conn)
|
|
{
|
|
Ok(x) => x,
|
|
Err(e) => {
|
|
return HttpResponse::InternalServerError().body(format!("{:?}", e));
|
|
}
|
|
};
|
|
|
|
templates::Posts { posts }.to_response()
|
|
}
|
|
|
|
#[get("/")]
|
|
async fn index() -> HttpResponse {
|
|
templates::Index.to_response()
|
|
}
|
|
|
|
#[get("/about")]
|
|
async fn about() -> HttpResponse {
|
|
templates::About.to_response()
|
|
}
|
|
|
|
#[get("/posts/{slug}")]
|
|
async fn post_by_slug(
|
|
db_pool: web::Data<db::DbPool>,
|
|
redis_pool: web::Data<cache::RedisPool>,
|
|
path: web::Path<String>,
|
|
) -> HttpResponse {
|
|
let slug = path.into_inner();
|
|
|
|
let db_conn = &mut match db_pool.get() {
|
|
Ok(x) => x,
|
|
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
|
|
};
|
|
let redis_conn = &mut match redis_pool.get() {
|
|
Ok(x) => x,
|
|
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
|
|
};
|
|
|
|
let post_stripped: Option<(i32, String)> = match db::schema::posts::table
|
|
.select((db::schema::posts::id, db::schema::posts::name))
|
|
.filter(db::schema::posts::slug.eq(&slug))
|
|
.filter(db::schema::posts::active)
|
|
.get_result::<(i32, String)>(db_conn)
|
|
.optional()
|
|
{
|
|
Ok(x) => x,
|
|
Err(e) => {
|
|
return HttpResponse::InternalServerError().body(format!("{:?}", e));
|
|
}
|
|
};
|
|
|
|
match post_stripped {
|
|
Some(stripped) => {
|
|
let (stripped_id, stripped_name) = stripped;
|
|
|
|
let key = cache::keys::post_content(stripped_id);
|
|
|
|
match match redis::cmd("GET")
|
|
.arg(&key)
|
|
.query::<Option<String>>(redis_conn.deref_mut())
|
|
{
|
|
Ok(x) => x,
|
|
Err(e) => return HttpResponse::InternalServerError().body(format!("{:?}", e)),
|
|
} {
|
|
Some(s) => templates::PostBySlug {
|
|
name: stripped_name,
|
|
slug,
|
|
content: s,
|
|
}
|
|
.to_response(),
|
|
None => {
|
|
let post = match db::schema::posts::table
|
|
.filter(db::schema::posts::id.eq(stripped_id))
|
|
.first::<db::models::Post>(db_conn)
|
|
{
|
|
Ok(x) => x,
|
|
Err(e) => {
|
|
return HttpResponse::InternalServerError().body(format!("{:?}", e));
|
|
}
|
|
};
|
|
|
|
let html = markdown::to_html(&post.content);
|
|
|
|
match redis::cmd("SET")
|
|
.arg(&key)
|
|
.arg(&html)
|
|
.query::<Option<String>>(redis_conn.deref_mut())
|
|
{
|
|
Ok(x) => x,
|
|
Err(e) => {
|
|
return HttpResponse::InternalServerError().body(format!("{:?}", e))
|
|
}
|
|
};
|
|
if let Err(e) = redis::cmd("EXPIRE")
|
|
.arg(key)
|
|
.arg(config::CONFIG.cache_post_content_ttl)
|
|
.query::<()>(redis_conn.deref_mut())
|
|
{
|
|
return HttpResponse::InternalServerError().body(format!("{:?}", e));
|
|
}
|
|
|
|
templates::PostBySlug {
|
|
name: post.name,
|
|
slug: post.slug,
|
|
content: html,
|
|
}
|
|
.to_response()
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
let mut resp = templates::StatusCode {
|
|
status_code: http::StatusCode::NOT_FOUND,
|
|
message: Some("this post does not exists... yet".to_string()),
|
|
}
|
|
.to_response();
|
|
*resp.status_mut() = http::StatusCode::NOT_FOUND;
|
|
|
|
resp
|
|
}
|
|
}
|
|
}
|
|
|
|
fn setup_routes(cfg: &mut web::ServiceConfig) {
|
|
let generated = static_dir::generate();
|
|
|
|
cfg.service(index)
|
|
.service(about)
|
|
.service(posts)
|
|
.service(ResourceFiles::new("/static", generated))
|
|
.service(post_by_slug)
|
|
.default_service(web::route().to(not_found));
|
|
}
|
|
|
|
pub fn init(cfg: &mut web::ServiceConfig) {
|
|
cfg.app_data(web::Data::new(db::pool().unwrap()))
|
|
.app_data(web::Data::new(cache::pool().unwrap()));
|
|
|
|
setup_routes(cfg);
|
|
}
|