diff --git a/nixin_farm_ssr/assets/views/service/create.html b/nixin_farm_ssr/assets/views/service/create.html new file mode 100644 index 0000000..e6b676a --- /dev/null +++ b/nixin_farm_ssr/assets/views/service/create.html @@ -0,0 +1,59 @@ +{% extends "base.html" %} + +{% block title %} +Create service +{% endblock title %} + +{% block content %} +
+
+

Create new service

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

Edit service: {{ item.id }}

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

service

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

View service: {{ item.id }}

+
+
+ +
+
+ +
+
+ +
+
+Back to services +
+{% endblock content %} diff --git a/nixin_farm_ssr/migration/src/lib.rs b/nixin_farm_ssr/migration/src/lib.rs index 1e23289..9355d87 100644 --- a/nixin_farm_ssr/migration/src/lib.rs +++ b/nixin_farm_ssr/migration/src/lib.rs @@ -7,6 +7,7 @@ mod m20231103_114510_notes; mod m20241016_181828_servers; mod m20241021_121449_bundles; +mod m20241021_121806_services; pub struct Migrator; #[async_trait::async_trait] @@ -17,6 +18,7 @@ impl MigratorTrait for Migrator { Box::new(m20231103_114510_notes::Migration), Box::new(m20241016_181828_servers::Migration), Box::new(m20241021_121449_bundles::Migration), + Box::new(m20241021_121806_services::Migration), ] } } \ No newline at end of file diff --git a/nixin_farm_ssr/migration/src/m20241021_121806_services.rs b/nixin_farm_ssr/migration/src/m20241021_121806_services.rs new file mode 100644 index 0000000..c1dbaf8 --- /dev/null +++ b/nixin_farm_ssr/migration/src/m20241021_121806_services.rs @@ -0,0 +1,39 @@ +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(Services::Table) + .col(pk_auto(Services::Id)) + .col(string_uniq(Services::Name)) + .col(text_null(Services::Description)) + .col(text_null(Services::Configuration)) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .drop_table(Table::drop().table(Services::Table).to_owned()) + .await + } +} + +#[derive(DeriveIden)] +enum Services { + Table, + Id, + Name, + Description, + Configuration, + +} + + diff --git a/nixin_farm_ssr/src/app.rs b/nixin_farm_ssr/src/app.rs index 13d44dd..81d0c80 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::service::routes()) .add_route(controllers::bundle::routes()) .add_route(controllers::server::routes()) .add_route(controllers::notes::routes()) diff --git a/nixin_farm_ssr/src/controllers/mod.rs b/nixin_farm_ssr/src/controllers/mod.rs index a4a1c5f..3a2ad1b 100644 --- a/nixin_farm_ssr/src/controllers/mod.rs +++ b/nixin_farm_ssr/src/controllers/mod.rs @@ -3,4 +3,5 @@ pub mod notes; pub mod user; pub mod server; -pub mod bundle; \ No newline at end of file +pub mod bundle; +pub mod service; \ No newline at end of file diff --git a/nixin_farm_ssr/src/controllers/service.rs b/nixin_farm_ssr/src/controllers/service.rs new file mode 100644 index 0000000..0684574 --- /dev/null +++ b/nixin_farm_ssr/src/controllers/service.rs @@ -0,0 +1,117 @@ +#![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::services::{ActiveModel, Column, Entity, Model}, + views, +}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Params { + pub name: String, + pub description: Option, + pub configuration: Option, + } + +impl Params { + fn update(&self, item: &mut ActiveModel) { + item.name = Set(self.name.clone()); + item.description = Set(self.description.clone()); + item.configuration = Set(self.configuration.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::service::list(&v, &item) +} + +#[debug_handler] +pub async fn new( + ViewEngine(v): ViewEngine, + State(_ctx): State, +) -> Result { + views::service::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::service::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::service::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::service::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("services/") + .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/models/_entities/mod.rs b/nixin_farm_ssr/src/models/_entities/mod.rs index aa030b3..61b59ff 100644 --- a/nixin_farm_ssr/src/models/_entities/mod.rs +++ b/nixin_farm_ssr/src/models/_entities/mod.rs @@ -5,4 +5,5 @@ pub mod prelude; pub mod bundles; pub mod notes; pub mod servers; +pub mod services; pub mod users; diff --git a/nixin_farm_ssr/src/models/_entities/prelude.rs b/nixin_farm_ssr/src/models/_entities/prelude.rs index 309156d..d605e42 100644 --- a/nixin_farm_ssr/src/models/_entities/prelude.rs +++ b/nixin_farm_ssr/src/models/_entities/prelude.rs @@ -3,4 +3,5 @@ pub use super::bundles::Entity as Bundles; pub use super::notes::Entity as Notes; pub use super::servers::Entity as Servers; +pub use super::services::Entity as Services; pub use super::users::Entity as Users; diff --git a/nixin_farm_ssr/src/models/_entities/services.rs b/nixin_farm_ssr/src/models/_entities/services.rs new file mode 100644 index 0000000..64c1b27 --- /dev/null +++ b/nixin_farm_ssr/src/models/_entities/services.rs @@ -0,0 +1,22 @@ +//! `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 = "services")] +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, + #[sea_orm(column_type = "Text", nullable)] + pub configuration: Option, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] +pub enum Relation {} diff --git a/nixin_farm_ssr/src/models/mod.rs b/nixin_farm_ssr/src/models/mod.rs index 5640eff..e2fdcc6 100644 --- a/nixin_farm_ssr/src/models/mod.rs +++ b/nixin_farm_ssr/src/models/mod.rs @@ -3,3 +3,4 @@ pub mod notes; pub mod users; pub mod servers; pub mod bundles; +pub mod services; diff --git a/nixin_farm_ssr/src/models/services.rs b/nixin_farm_ssr/src/models/services.rs new file mode 100644 index 0000000..eb04982 --- /dev/null +++ b/nixin_farm_ssr/src/models/services.rs @@ -0,0 +1,7 @@ +use sea_orm::entity::prelude::*; +use super::_entities::services::{ActiveModel, Entity}; +pub type Services = Entity; + +impl ActiveModelBehavior for ActiveModel { + // extend activemodel below (keep comment for generators) +} diff --git a/nixin_farm_ssr/src/views/mod.rs b/nixin_farm_ssr/src/views/mod.rs index 49fd8b1..ae02a00 100644 --- a/nixin_farm_ssr/src/views/mod.rs +++ b/nixin_farm_ssr/src/views/mod.rs @@ -2,4 +2,5 @@ pub mod auth; pub mod user; pub mod server; -pub mod bundle; \ No newline at end of file +pub mod bundle; +pub mod service; \ No newline at end of file diff --git a/nixin_farm_ssr/src/views/service.rs b/nixin_farm_ssr/src/views/service.rs new file mode 100644 index 0000000..1fb12d0 --- /dev/null +++ b/nixin_farm_ssr/src/views/service.rs @@ -0,0 +1,39 @@ +use loco_rs::prelude::*; + +use crate::models::_entities::services; + +/// Render a list view of services. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn list(v: &impl ViewRenderer, items: &Vec) -> Result { + format::render().view(v, "service/list.html", data!({"items": items})) +} + +/// Render a single service view. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn show(v: &impl ViewRenderer, item: &services::Model) -> Result { + format::render().view(v, "service/show.html", data!({"item": item})) +} + +/// Render a service create form. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn create(v: &impl ViewRenderer) -> Result { + format::render().view(v, "service/create.html", data!({})) +} + +/// Render a service edit form. +/// +/// # Errors +/// +/// When there is an issue with rendering the view. +pub fn edit(v: &impl ViewRenderer, item: &services::Model) -> Result { + format::render().view(v, "service/edit.html", data!({"item": item})) +} diff --git a/nixin_farm_ssr/tests/models/mod.rs b/nixin_farm_ssr/tests/models/mod.rs index fdeaf31..3c18f56 100644 --- a/nixin_farm_ssr/tests/models/mod.rs +++ b/nixin_farm_ssr/tests/models/mod.rs @@ -1,4 +1,5 @@ mod users; mod servers; -mod bundles; \ No newline at end of file +mod bundles; +mod services; \ No newline at end of file diff --git a/nixin_farm_ssr/tests/models/services.rs b/nixin_farm_ssr/tests/models/services.rs new file mode 100644 index 0000000..66cdb82 --- /dev/null +++ b/nixin_farm_ssr/tests/models/services.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); +}