#[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::{context, Template}; use sea_orm::{entity::*, query::*}; use sea_orm_rocket::{Connection, Database}; mod pool; use pool::Db; mod setup; mod post; pub use post::Entity as Post; const DEFAULT_POSTS_PER_PAGE: usize = 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(); post::ActiveModel { title: Set(form.title.to_owned()), text: Set(form.text.to_owned()), ..Default::default() } .save(db) .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 post: post::ActiveModel = Post::find_by_id(id).one(db).await.unwrap().unwrap().into(); let form = post_form.into_inner(); db.transaction::<_, (), sea_orm::DbErr>(|txn| { Box::pin(async move { post::ActiveModel { id: post.id, title: Set(form.title.to_owned()), text: Set(form.text.to_owned()), } .save(txn) .await .expect("could not edit post"); Ok(()) }) }) .await .unwrap(); 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"); } // Setup paginator let paginator = Post::find() .order_by_asc(post::Column::Id) .paginate(db, posts_per_page); let num_pages = paginator.num_pages().await.ok().unwrap(); // Fetch paginated posts let posts = paginator .fetch_page(page - 1) .await .expect("could not retrieve posts"); Template::render( "index", context! { 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 = Post::find_by_id(id) .one(db) .await .expect("could not find post"); Template::render( "edit", context! { post: post, }, ) } #[delete("/")] async fn delete(conn: Connection<'_, Db>, id: i32) -> Flash { let db = conn.into_inner(); let post: post::ActiveModel = Post::find_by_id(id).one(db).await.unwrap().unwrap().into(); post.delete(db).await.unwrap(); Flash::success(Redirect::to("/"), "Post successfully deleted.") } #[delete("/")] async fn destroy(conn: Connection<'_, Db>) -> Result<(), rocket::response::Debug> { let db = conn.into_inner(); Post::delete_many().exec(db).await.unwrap(); Ok(()) } #[catch(404)] pub fn not_found(req: &Request<'_>) -> Template { Template::render( "error/404", context! { uri: req.uri() }, ) } async fn run_migrations(rocket: Rocket) -> fairing::Result { let conn = &Db::fetch(&rocket).unwrap().conn; let _ = setup::create_post_table(conn).await; Ok(rocket) } #[launch] fn rocket() -> _ { 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()) }