#[macro_use] extern crate rocket; use rocket::fairing::{self, AdHoc}; use rocket::form::{Context, Form}; use rocket::fs::{relative, FileServer}; use rocket::request::FlashMessage; use rocket::response::{Flash, Redirect}; use rocket::{Build, Request, Rocket}; use rocket_dyn_templates::Template; use rocket_example_service::{Mutation, Query}; use serde_json::json; use migration::MigratorTrait; use sea_orm_rocket::{Connection, Database}; mod pool; use pool::Db; pub use entity::post; pub use entity::post::Entity as Post; const DEFAULT_POSTS_PER_PAGE: u64 = 5; #[get("/new")] async fn new() -> Template { Template::render("new", &Context::default()) } #[post("/", data = "")] async fn create(conn: Connection<'_, Db>, post_form: Form) -> Flash { let db = conn.into_inner(); let form = post_form.into_inner(); Mutation::create_post(db, form) .await .expect("could not insert post"); Flash::success(Redirect::to("/"), "Post successfully added.") } #[post("/", data = "")] async fn update( conn: Connection<'_, Db>, id: i32, post_form: Form, ) -> Flash { let db = conn.into_inner(); let form = post_form.into_inner(); Mutation::update_post_by_id(db, id, form) .await .expect("could not update post"); Flash::success(Redirect::to("/"), "Post successfully edited.") } #[get("/?&")] async fn list( conn: Connection<'_, Db>, page: Option, posts_per_page: Option, flash: Option>, ) -> Template { let db = conn.into_inner(); // Set page number and items per page let page = page.unwrap_or(1); let posts_per_page = posts_per_page.unwrap_or(DEFAULT_POSTS_PER_PAGE); if page == 0 { panic!("Page number cannot be zero"); } let (posts, num_pages) = Query::find_posts_in_page(db, page, posts_per_page) .await .expect("Cannot find posts in page"); Template::render( "index", json! ({ "page": page, "posts_per_page": posts_per_page, "num_pages": num_pages, "posts": posts, "flash": flash.map(FlashMessage::into_inner), }), ) } #[get("/")] async fn edit(conn: Connection<'_, Db>, id: i32) -> Template { let db = conn.into_inner(); let post: Option = Query::find_post_by_id(db, id) .await .expect("could not find post"); Template::render( "edit", json! ({ "post": post, }), ) } #[delete("/")] async fn delete(conn: Connection<'_, Db>, id: i32) -> Flash { let db = conn.into_inner(); Mutation::delete_post(db, id) .await .expect("could not delete post"); Flash::success(Redirect::to("/"), "Post successfully deleted.") } #[delete("/")] async fn destroy(conn: Connection<'_, Db>) -> Result<(), rocket::response::Debug> { let db = conn.into_inner(); Mutation::delete_all_posts(db) .await .map_err(|e| e.to_string())?; Ok(()) } #[catch(404)] pub fn not_found(req: &Request<'_>) -> Template { Template::render( "error/404", json! ({ "uri": req.uri() }), ) } async fn run_migrations(rocket: Rocket) -> fairing::Result { let conn = &Db::fetch(&rocket).unwrap().conn; let _ = migration::Migrator::up(conn, None).await; Ok(rocket) } #[tokio::main] async fn start() -> Result<(), rocket::Error> { rocket::build() .attach(Db::init()) .attach(AdHoc::try_on_ignite("Migrations", run_migrations)) .mount("/", FileServer::from(relative!("/static"))) .mount( "/", routes![new, create, delete, destroy, list, edit, update], ) .register("/", catchers![not_found]) .attach(Template::fairing()) .launch() .await .map(|_| ()) } pub fn main() { let result = start(); println!("Rocket: deorbit."); if let Some(err) = result.err() { println!("Error: {err}"); } }