From d9a6cf87569be4a6a8a53269a5261774fe21eb84 Mon Sep 17 00:00:00 2001 From: Fabrice Bellamy <12b@distrilab.fr> Date: Mon, 21 Oct 2024 14:16:25 +0200 Subject: [PATCH] cargo loco generate scaffold bundle name:string^ description:text --htmx --- .../assets/views/bundle/create.html | 54 ++++++++ nixin_farm_ssr/assets/views/bundle/edit.html | 73 +++++++++++ nixin_farm_ssr/assets/views/bundle/list.html | 27 ++++ nixin_farm_ssr/assets/views/bundle/show.html | 19 +++ nixin_farm_ssr/migration/src/lib.rs | 2 + .../migration/src/m20241021_121449_bundles.rs | 37 ++++++ nixin_farm_ssr/src/app.rs | 1 + nixin_farm_ssr/src/controllers/bundle.rs | 115 ++++++++++++++++++ nixin_farm_ssr/src/controllers/mod.rs | 3 +- .../src/models/_entities/bundles.rs | 20 +++ nixin_farm_ssr/src/models/_entities/mod.rs | 1 + .../src/models/_entities/prelude.rs | 1 + nixin_farm_ssr/src/models/bundles.rs | 7 ++ nixin_farm_ssr/src/models/mod.rs | 1 + nixin_farm_ssr/src/views/bundle.rs | 39 ++++++ nixin_farm_ssr/src/views/mod.rs | 3 +- nixin_farm_ssr/tests/models/bundles.rs | 31 +++++ nixin_farm_ssr/tests/models/mod.rs | 3 +- 18 files changed, 434 insertions(+), 3 deletions(-) create mode 100644 nixin_farm_ssr/assets/views/bundle/create.html create mode 100644 nixin_farm_ssr/assets/views/bundle/edit.html create mode 100644 nixin_farm_ssr/assets/views/bundle/list.html create mode 100644 nixin_farm_ssr/assets/views/bundle/show.html create mode 100644 nixin_farm_ssr/migration/src/m20241021_121449_bundles.rs create mode 100644 nixin_farm_ssr/src/controllers/bundle.rs create mode 100644 nixin_farm_ssr/src/models/_entities/bundles.rs create mode 100644 nixin_farm_ssr/src/models/bundles.rs create mode 100644 nixin_farm_ssr/src/views/bundle.rs create mode 100644 nixin_farm_ssr/tests/models/bundles.rs diff --git a/nixin_farm_ssr/assets/views/bundle/create.html b/nixin_farm_ssr/assets/views/bundle/create.html new file mode 100644 index 0000000..c1d3e13 --- /dev/null +++ b/nixin_farm_ssr/assets/views/bundle/create.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} + +{% block title %} +Create bundle +{% endblock title %} + +{% block content %} +
+
+

Create new bundle

+
+
+ +
+ +
+
+ +
+ +
+
+
+ +
+
+
+{% endblock content %} + +{% block js %} + +{% endblock js %} \ No newline at end of file diff --git a/nixin_farm_ssr/assets/views/bundle/edit.html b/nixin_farm_ssr/assets/views/bundle/edit.html new file mode 100644 index 0000000..1cd784d --- /dev/null +++ b/nixin_farm_ssr/assets/views/bundle/edit.html @@ -0,0 +1,73 @@ +{% extends "base.html" %} + +{% block title %} +Edit bundle: {{ item.id }} +{% endblock title %} + +{% block content %} +

Edit bundle: {{ item.id }}

+
+
+
+
+ +
+ +
+
+ +
+ +
+
+
+ + +
+
+ +
+
+Back to bundle +
+{% endblock content %} + +{% block js %} + +{% endblock js %} \ No newline at end of file diff --git a/nixin_farm_ssr/assets/views/bundle/list.html b/nixin_farm_ssr/assets/views/bundle/list.html new file mode 100644 index 0000000..22b6e35 --- /dev/null +++ b/nixin_farm_ssr/assets/views/bundle/list.html @@ -0,0 +1,27 @@ +{% extends "base.html" %} + +{% block title %} +List of bundle +{% endblock title %} + +{% block content %} +

bundle

+
+ {% for item in items %} +
+
+ +
+
+ +
+ Edit + View +
+ {% endfor %} + +
+
+ New bundle +
+{% endblock content %} diff --git a/nixin_farm_ssr/assets/views/bundle/show.html b/nixin_farm_ssr/assets/views/bundle/show.html new file mode 100644 index 0000000..1ca56ee --- /dev/null +++ b/nixin_farm_ssr/assets/views/bundle/show.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} + +{% block title %} +View bundle: {{ item.id }} +{% endblock title %} + +{% block content %} +

View bundle: {{ item.id }}

+
+
+ +
+
+ +
+
+Back to bundles +
+{% endblock content %} diff --git a/nixin_farm_ssr/migration/src/lib.rs b/nixin_farm_ssr/migration/src/lib.rs index 056ac3e..1e23289 100644 --- a/nixin_farm_ssr/migration/src/lib.rs +++ b/nixin_farm_ssr/migration/src/lib.rs @@ -6,6 +6,7 @@ mod m20220101_000001_users; mod m20231103_114510_notes; mod m20241016_181828_servers; +mod m20241021_121449_bundles; pub struct Migrator; #[async_trait::async_trait] @@ -15,6 +16,7 @@ impl MigratorTrait for Migrator { Box::new(m20220101_000001_users::Migration), Box::new(m20231103_114510_notes::Migration), Box::new(m20241016_181828_servers::Migration), + Box::new(m20241021_121449_bundles::Migration), ] } } \ No newline at end of file diff --git a/nixin_farm_ssr/migration/src/m20241021_121449_bundles.rs b/nixin_farm_ssr/migration/src/m20241021_121449_bundles.rs new file mode 100644 index 0000000..b6d9fd1 --- /dev/null +++ b/nixin_farm_ssr/migration/src/m20241021_121449_bundles.rs @@ -0,0 +1,37 @@ +use loco_rs::schema::table_auto_tz; +use sea_orm_migration::{prelude::*, schema::*}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .create_table( + table_auto_tz(Bundles::Table) + .col(pk_auto(Bundles::Id)) + .col(string_uniq(Bundles::Name)) + .col(text_null(Bundles::Description)) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Bundles::Table).to_owned()) + .await + } +} + +#[derive(DeriveIden)] +enum Bundles { + Table, + Id, + Name, + Description, + +} + + diff --git a/nixin_farm_ssr/src/app.rs b/nixin_farm_ssr/src/app.rs index 1c9a468..13d44dd 100644 --- a/nixin_farm_ssr/src/app.rs +++ b/nixin_farm_ssr/src/app.rs @@ -50,6 +50,7 @@ impl Hooks for App { fn routes(_ctx: &AppContext) -> AppRoutes { AppRoutes::with_default_routes() + .add_route(controllers::bundle::routes()) .add_route(controllers::server::routes()) .add_route(controllers::notes::routes()) .add_route(controllers::auth::routes()) diff --git a/nixin_farm_ssr/src/controllers/bundle.rs b/nixin_farm_ssr/src/controllers/bundle.rs new file mode 100644 index 0000000..0f91433 --- /dev/null +++ b/nixin_farm_ssr/src/controllers/bundle.rs @@ -0,0 +1,115 @@ +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::unnecessary_struct_initialization)] +#![allow(clippy::unused_async)] +use loco_rs::prelude::*; +use serde::{Deserialize, Serialize}; +use sea_orm::{sea_query::Order, QueryOrder}; +use axum::debug_handler; + +use crate::{ + models::_entities::bundles::{ActiveModel, Column, Entity, Model}, + views, +}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Params { + pub name: String, + pub description: Option, + } + +impl Params { + fn update(&self, item: &mut ActiveModel) { + item.name = Set(self.name.clone()); + item.description = Set(self.description.clone()); + } +} + +async fn load_item(ctx: &AppContext, id: i32) -> Result { + let item = Entity::find_by_id(id).one(&ctx.db).await?; + item.ok_or_else(|| Error::NotFound) +} + +#[debug_handler] +pub async fn list( + ViewEngine(v): ViewEngine, + State(ctx): State, +) -> Result { + let item = Entity::find() + .order_by(Column::Id, Order::Desc) + .all(&ctx.db) + .await?; + views::bundle::list(&v, &item) +} + +#[debug_handler] +pub async fn new( + ViewEngine(v): ViewEngine, + State(_ctx): State, +) -> Result { + views::bundle::create(&v) +} + +#[debug_handler] +pub async fn update( + Path(id): Path, + State(ctx): State, + Json(params): Json, +) -> Result { + let item = load_item(&ctx, id).await?; + let mut item = item.into_active_model(); + params.update(&mut item); + let item = item.update(&ctx.db).await?; + format::json(item) +} + +#[debug_handler] +pub async fn edit( + Path(id): Path, + ViewEngine(v): ViewEngine, + State(ctx): State, +) -> Result { + let item = load_item(&ctx, id).await?; + views::bundle::edit(&v, &item) +} + +#[debug_handler] +pub async fn show( + Path(id): Path, + ViewEngine(v): ViewEngine, + State(ctx): State, +) -> Result { + let item = load_item(&ctx, id).await?; + views::bundle::show(&v, &item) +} + +#[debug_handler] +pub async fn add( + ViewEngine(v): ViewEngine, + State(ctx): State, + Json(params): Json, +) -> Result { + let mut item = ActiveModel { + ..Default::default() + }; + params.update(&mut item); + let item = item.insert(&ctx.db).await?; + views::bundle::show(&v, &item) +} + +#[debug_handler] +pub async fn remove(Path(id): Path, State(ctx): State) -> Result { + load_item(&ctx, id).await?.delete(&ctx.db).await?; + format::empty() +} + +pub fn routes() -> Routes { + Routes::new() + .prefix("bundles/") + .add("/", get(list)) + .add("/", post(add)) + .add("new", get(new)) + .add(":id", get(show)) + .add(":id/edit", get(edit)) + .add(":id", post(update)) + .add(":id", delete(remove)) +} diff --git a/nixin_farm_ssr/src/controllers/mod.rs b/nixin_farm_ssr/src/controllers/mod.rs index baf6605..a4a1c5f 100644 --- a/nixin_farm_ssr/src/controllers/mod.rs +++ b/nixin_farm_ssr/src/controllers/mod.rs @@ -2,4 +2,5 @@ pub mod auth; pub mod notes; pub mod user; -pub mod server; \ No newline at end of file +pub mod server; +pub mod bundle; \ No newline at end of file diff --git a/nixin_farm_ssr/src/models/_entities/bundles.rs b/nixin_farm_ssr/src/models/_entities/bundles.rs new file mode 100644 index 0000000..8829621 --- /dev/null +++ b/nixin_farm_ssr/src/models/_entities/bundles.rs @@ -0,0 +1,20 @@ +//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 + +use sea_orm::entity::prelude::*; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)] +#[sea_orm(table_name = "bundles")] +pub struct Model { + pub created_at: DateTimeWithTimeZone, + pub updated_at: DateTimeWithTimeZone, + #[sea_orm(primary_key)] + pub id: i32, + #[sea_orm(unique)] + pub name: String, + #[sea_orm(column_type = "Text", nullable)] + pub description: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} diff --git a/nixin_farm_ssr/src/models/_entities/mod.rs b/nixin_farm_ssr/src/models/_entities/mod.rs index fa23d39..aa030b3 100644 --- a/nixin_farm_ssr/src/models/_entities/mod.rs +++ b/nixin_farm_ssr/src/models/_entities/mod.rs @@ -2,6 +2,7 @@ pub mod prelude; +pub mod bundles; pub mod notes; pub mod servers; pub mod users; diff --git a/nixin_farm_ssr/src/models/_entities/prelude.rs b/nixin_farm_ssr/src/models/_entities/prelude.rs index 2a9300a..309156d 100644 --- a/nixin_farm_ssr/src/models/_entities/prelude.rs +++ b/nixin_farm_ssr/src/models/_entities/prelude.rs @@ -1,5 +1,6 @@ //! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 +pub use super::bundles::Entity as Bundles; pub use super::notes::Entity as Notes; pub use super::servers::Entity as Servers; pub use super::users::Entity as Users; diff --git a/nixin_farm_ssr/src/models/bundles.rs b/nixin_farm_ssr/src/models/bundles.rs new file mode 100644 index 0000000..5398c9e --- /dev/null +++ b/nixin_farm_ssr/src/models/bundles.rs @@ -0,0 +1,7 @@ +use sea_orm::entity::prelude::*; +use super::_entities::bundles::{ActiveModel, Entity}; +pub type Bundles = Entity; + +impl ActiveModelBehavior for ActiveModel { + // extend activemodel below (keep comment for generators) +} diff --git a/nixin_farm_ssr/src/models/mod.rs b/nixin_farm_ssr/src/models/mod.rs index 2622fcb..5640eff 100644 --- a/nixin_farm_ssr/src/models/mod.rs +++ b/nixin_farm_ssr/src/models/mod.rs @@ -2,3 +2,4 @@ pub mod _entities; pub mod notes; pub mod users; pub mod servers; +pub mod bundles; diff --git a/nixin_farm_ssr/src/views/bundle.rs b/nixin_farm_ssr/src/views/bundle.rs new file mode 100644 index 0000000..91f1bfe --- /dev/null +++ b/nixin_farm_ssr/src/views/bundle.rs @@ -0,0 +1,39 @@ +use loco_rs::prelude::*; + +use crate::models::_entities::bundles; + +/// Render a list view of bundles. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn list(v: &impl ViewRenderer, items: &Vec) -> Result { + format::render().view(v, "bundle/list.html", data!({"items": items})) +} + +/// Render a single bundle view. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn show(v: &impl ViewRenderer, item: &bundles::Model) -> Result { + format::render().view(v, "bundle/show.html", data!({"item": item})) +} + +/// Render a bundle create form. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn create(v: &impl ViewRenderer) -> Result { + format::render().view(v, "bundle/create.html", data!({})) +} + +/// Render a bundle edit form. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn edit(v: &impl ViewRenderer, item: &bundles::Model) -> Result { + format::render().view(v, "bundle/edit.html", data!({"item": item})) +} diff --git a/nixin_farm_ssr/src/views/mod.rs b/nixin_farm_ssr/src/views/mod.rs index b8613a9..49fd8b1 100644 --- a/nixin_farm_ssr/src/views/mod.rs +++ b/nixin_farm_ssr/src/views/mod.rs @@ -1,4 +1,5 @@ pub mod auth; pub mod user; -pub mod server; \ No newline at end of file +pub mod server; +pub mod bundle; \ No newline at end of file diff --git a/nixin_farm_ssr/tests/models/bundles.rs b/nixin_farm_ssr/tests/models/bundles.rs new file mode 100644 index 0000000..66cdb82 --- /dev/null +++ b/nixin_farm_ssr/tests/models/bundles.rs @@ -0,0 +1,31 @@ +use nixin_farm_ssr::app::App; +use loco_rs::testing; +use serial_test::serial; + +macro_rules! configure_insta { + ($($expr:expr),*) => { + let mut settings = insta::Settings::clone_current(); + settings.set_prepend_module_to_snapshot(false); + let _guard = settings.bind_to_scope(); + }; +} + +#[tokio::test] +#[serial] +async fn test_model() { + configure_insta!(); + + let boot = testing::boot_test::().await.unwrap(); + testing::seed::(&boot.app_context.db).await.unwrap(); + + // query your model, e.g.: + // + // let item = models::posts::Model::find_by_pid( + // &boot.app_context.db, + // "11111111-1111-1111-1111-111111111111", + // ) + // .await; + + // snapshot the result: + // assert_debug_snapshot!(item); +} diff --git a/nixin_farm_ssr/tests/models/mod.rs b/nixin_farm_ssr/tests/models/mod.rs index 22e060c..fdeaf31 100644 --- a/nixin_farm_ssr/tests/models/mod.rs +++ b/nixin_farm_ssr/tests/models/mod.rs @@ -1,3 +1,4 @@ mod users; -mod servers; \ No newline at end of file +mod servers; +mod bundles; \ No newline at end of file