blog/backend/src/web/mod.rs
Dominic Grimm 765fcc67dd
All checks were successful
continuous-integration/drone/push Build is passing
Update ci
2023-02-12 12:59:17 +01:00

194 lines
5.5 KiB
Rust

use actix_web::{get, http, web, HttpResponse};
use actix_web_static_files::ResourceFiles;
use anyhow::Result;
use askama_actix::TemplateToResponse;
use diesel::prelude::*;
use crate::{cache, db};
pub mod templates;
use templates::TemplateToResponseWithStatusCode;
pub mod static_dir {
include!(concat!(env!("OUT_DIR"), "/generated.rs"));
}
async fn not_found() -> HttpResponse {
templates::StatusCode {
status_code: http::StatusCode::NOT_FOUND,
message: Some("maybe try a correct url?".to_string()),
}
.to_response_with_status_code(http::StatusCode::NOT_FOUND)
}
#[get("/")]
async fn index() -> HttpResponse {
templates::Index.to_response()
}
#[get("/about")]
async fn about() -> HttpResponse {
templates::About.to_response()
}
pub fn get_tags_by_post(id: i32, db_conn: &mut diesel::PgConnection) -> Result<Vec<String>> {
Ok(db::schema::tags::table
.select(db::schema::tags::name)
.filter(
db::schema::tags::id.eq_any(
db::schema::post_tags::table
.select(db::schema::post_tags::tag_id)
.filter(db::schema::post_tags::post_id.eq(id))
.load::<i32>(db_conn)?,
),
)
.order(db::schema::tags::name)
.load::<String>(db_conn)?)
}
#[get("/posts")]
async fn posts(
db_pool: web::Data<db::DbPool>,
redis_pool: web::Data<cache::RedisPool>,
) -> HttpResponse {
let db_conn = &mut match db_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let redis_conn = &mut match redis_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let posts = match cache::cache_posts(db_conn, redis_conn) {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
templates::Posts { posts }.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(_) => return HttpResponse::InternalServerError().finish(),
};
let redis_conn = &mut match redis_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
if let Some(post_id) = match db::schema::posts::table
.select(db::schema::posts::id)
.filter(db::schema::posts::slug.eq(slug))
.filter(db::schema::posts::active)
.first::<i32>(db_conn)
.optional()
{
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
} {
let post = match cache::cache_post(post_id, db_conn, redis_conn) {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
templates::PostBySlug { post }.to_response()
} else {
templates::StatusCode {
status_code: http::StatusCode::NOT_FOUND,
message: Some("this post does not exists... yet".to_string()),
}
.to_response_with_status_code(http::StatusCode::NOT_FOUND)
}
}
#[get("/tags")]
async fn tags(
db_pool: web::Data<db::DbPool>,
redis_pool: web::Data<cache::RedisPool>,
) -> HttpResponse {
let db_conn = &mut match db_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let redis_conn = &mut match redis_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let x = match cache::cache_tags(db_conn, redis_conn) {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
templates::Tags { tags: x }.to_response()
}
#[get("/tags/{name}")]
async fn tag_by_name(
db_pool: web::Data<db::DbPool>,
redis_pool: web::Data<cache::RedisPool>,
path: web::Path<String>,
) -> HttpResponse {
const MESSAGE: &str = "this post does not exists... yet";
let name = path.into_inner();
let db_conn = &mut match db_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let redis_conn = &mut match redis_pool.get() {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let tag_id = match db::schema::tags::table
.select(db::schema::tags::id)
.filter(db::schema::tags::name.eq(&name))
.first::<i32>(db_conn)
{
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
let posts_cache = match cache::cache_tag_posts(tag_id, db_conn, redis_conn) {
Ok(x) => x,
Err(_) => return HttpResponse::InternalServerError().finish(),
};
templates::TagByName {
name,
posts: posts_cache,
}
.to_response()
}
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)
.service(tags)
.service(tag_by_name)
.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);
}