* Move core implementations to a standalone crate * Set up integration test skeleton in `core` * Demonstrate mock testing with query * Move Rocket api code to a standalone crate * Add mock execution * Add MyDataMyConsent in COMMUNITY.md (#889) * Add MyDataMyConsent in COMMUNITY.md * Update MyDataMyConsent description in COMMUNITY.md * Update COMMUNITY.md Chronological order * [cli] bump sea-schema to 0.9.3 (SeaQL/sea-orm#876) * Update CHNAGELOG PR links * 0.9.1 CHANGELOG * Auto discover and run all issues & examples CI (#903) * Auto discover and run all [issues] CI * Auto discover and run all examples CI * Fixup * Testing * Test [issues] * Compile prepare_mock_db() conditionally based on "mock" feature * Update workflow job to run mock test if `core` folder exists * Update Actix3 example * Fix merge conflict human error * Update usize used in paginate to u64 (PR#789) * Update sea-orm version in the Rocket example to 0.10.0 * Fix GitHub workflow to run mock test for core crates * Increase the robustness of core crate check by verifying that the `core` folder is a crate * Update Actix(4) example * Update Axum example * Update GraphQL example * Update Jsonrpsee example * Update Poem example * Update Tonic example * Cargo fmt * Update Salvo example * Update path of core/Cargo.toml in README.md * Add mock test instruction in README.md * Refactoring * Fix Rocket examples Co-authored-by: Amit Goyani <63532626+itsAmitGoyani@users.noreply.github.com> Co-authored-by: Billy Chan <ccw.billy.123@gmail.com>
172 lines
4.1 KiB
Rust
172 lines
4.1 KiB
Rust
#[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_core::{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 = "<post_form>")]
|
|
async fn create(conn: Connection<'_, Db>, post_form: Form<post::Model>) -> Flash<Redirect> {
|
|
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("/<id>", data = "<post_form>")]
|
|
async fn update(
|
|
conn: Connection<'_, Db>,
|
|
id: i32,
|
|
post_form: Form<post::Model>,
|
|
) -> Flash<Redirect> {
|
|
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("/?<page>&<posts_per_page>")]
|
|
async fn list(
|
|
conn: Connection<'_, Db>,
|
|
page: Option<u64>,
|
|
posts_per_page: Option<u64>,
|
|
flash: Option<FlashMessage<'_>>,
|
|
) -> 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("/<id>")]
|
|
async fn edit(conn: Connection<'_, Db>, id: i32) -> Template {
|
|
let db = conn.into_inner();
|
|
|
|
let post: Option<post::Model> = Query::find_post_by_id(db, id)
|
|
.await
|
|
.expect("could not find post");
|
|
|
|
Template::render(
|
|
"edit",
|
|
json! ({
|
|
"post": post,
|
|
}),
|
|
)
|
|
}
|
|
|
|
#[delete("/<id>")]
|
|
async fn delete(conn: Connection<'_, Db>, id: i32) -> Flash<Redirect> {
|
|
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<String>> {
|
|
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<Build>) -> 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);
|
|
}
|
|
}
|