what does loco offers

This commit is contained in:
Priec
2026-05-15 22:31:26 +02:00
parent 0c25fa5d11
commit 8b7f883f14
22 changed files with 731 additions and 5 deletions

View File

@@ -51,6 +51,8 @@ impl Hooks for App {
fn routes(_ctx: &AppContext) -> AppRoutes {
AppRoutes::with_default_routes() // controller routes below
.add_route(controllers::home::routes())
.add_route(controllers::court::routes())
.add_route(controllers::auth::routes())
}
async fn connect_workers(ctx: &AppContext, queue: &Queue) -> Result<()> {
@@ -71,4 +73,4 @@ impl Hooks for App {
.await?;
Ok(())
}
}
}

View File

@@ -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 axum::response::Redirect;
use axum_extra::extract::Form;
use sea_orm::{sea_query::Order, QueryOrder};
use crate::{
models::_entities::courts::{ActiveModel, Column, Entity, Model},
views,
};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Params {
pub name: Option<String>,
pub surface: Option<String>,
pub indoor: Option<bool>,
}
impl Params {
fn update(&self, item: &mut ActiveModel) {
item.name = Set(self.name.clone());
item.surface = Set(self.surface.clone());
item.indoor = Set(self.indoor);
}
}
async fn load_item(ctx: &AppContext, id: i32) -> Result<Model> {
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<TeraView>,
State(ctx): State<AppContext>,
) -> Result<Response> {
let item = Entity::find()
.order_by(Column::Id, Order::Desc)
.all(&ctx.db)
.await?;
views::court::list(&v, &item)
}
#[debug_handler]
pub async fn new(
ViewEngine(v): ViewEngine<TeraView>,
State(_ctx): State<AppContext>,
) -> Result<Response> {
views::court::create(&v)
}
#[debug_handler]
pub async fn update(
Path(id): Path<i32>,
State(ctx): State<AppContext>,
Form(params): Form<Params>,
) -> Result<Redirect> {
let item = load_item(&ctx, id).await?;
let mut item = item.into_active_model();
params.update(&mut item);
item.update(&ctx.db).await?;
Ok(Redirect::to("../courts"))
}
#[debug_handler]
pub async fn edit(
Path(id): Path<i32>,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
) -> Result<Response> {
let item = load_item(&ctx, id).await?;
views::court::edit(&v, &item)
}
#[debug_handler]
pub async fn show(
Path(id): Path<i32>,
ViewEngine(v): ViewEngine<TeraView>,
State(ctx): State<AppContext>,
) -> Result<Response> {
let item = load_item(&ctx, id).await?;
views::court::show(&v, &item)
}
#[debug_handler]
pub async fn add(
State(ctx): State<AppContext>,
Form(params): Form<Params>,
) -> Result<Redirect> {
let mut item = ActiveModel {
..Default::default()
};
params.update(&mut item);
item.insert(&ctx.db).await?;
Ok(Redirect::to("courts"))
}
#[debug_handler]
pub async fn remove(Path(id): Path<i32>, State(ctx): State<AppContext>) -> Result<Response> {
load_item(&ctx, id).await?.delete(&ctx.db).await?;
format::empty()
}
pub fn routes() -> Routes {
Routes::new()
.prefix("courts/")
.add("/", get(list))
.add("/", post(add))
.add("new", get(new))
.add("{id}", get(show))
.add("{id}/edit", get(edit))
.add("{id}", delete(remove))
.add("{id}", post(update))
}

View File

@@ -0,0 +1,16 @@
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::unnecessary_struct_initialization)]
#![allow(clippy::unused_async)]
use loco_rs::prelude::*;
#[debug_handler]
pub async fn home(
ViewEngine(v): ViewEngine<TeraView>,
State(_ctx): State<AppContext>
) -> Result<Response> {
format::render().view(&v, "home/home.html", data!({}))
}
pub fn routes() -> Routes {
Routes::new().add("/", get(home))
}

View File

@@ -1 +1,4 @@
pub mod auth;
pub mod court;
pub mod home;

View File

@@ -0,0 +1,19 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.20
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "courts")]
pub struct Model {
pub created_at: DateTimeWithTimeZone,
pub updated_at: DateTimeWithTimeZone,
#[sea_orm(primary_key)]
pub id: i32,
pub name: Option<String>,
pub surface: Option<String>,
pub indoor: Option<bool>,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

View File

@@ -1,4 +1,6 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.20
pub mod prelude;
pub mod courts;
pub mod users;

View File

@@ -1,2 +1,4 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.20
pub use super::courts::Entity as Courts;
pub use super::users::Entity as Users;

View File

@@ -1,4 +1,4 @@
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.20
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};

View File

@@ -0,0 +1,28 @@
use sea_orm::entity::prelude::*;
pub use super::_entities::courts::{ActiveModel, Model, Entity};
pub type Courts = Entity;
#[async_trait::async_trait]
impl ActiveModelBehavior for ActiveModel {
async fn before_save<C>(self, _db: &C, insert: bool) -> std::result::Result<Self, DbErr>
where
C: ConnectionTrait,
{
if !insert && self.updated_at.is_unchanged() {
let mut this = self;
this.updated_at = sea_orm::ActiveValue::Set(chrono::Utc::now().into());
Ok(this)
} else {
Ok(self)
}
}
}
// implement your read-oriented logic here
impl Model {}
// implement your write-oriented logic here
impl ActiveModel {}
// implement your custom finders, selectors oriented logic here
impl Entity {}

View File

@@ -1,2 +1,3 @@
pub mod _entities;
pub mod users;
pub mod courts;

View File

@@ -0,0 +1,39 @@
use loco_rs::prelude::*;
use crate::models::_entities::courts;
/// Render a list view of `courts`.
///
/// # Errors
///
/// When there is an issue with rendering the view.
pub fn list(v: &impl ViewRenderer, items: &Vec<courts::Model>) -> Result<Response> {
format::render().view(v, "court/list.html", data!({"items": items}))
}
/// Render a single `court` view.
///
/// # Errors
///
/// When there is an issue with rendering the view.
pub fn show(v: &impl ViewRenderer, item: &courts::Model) -> Result<Response> {
format::render().view(v, "court/show.html", data!({"item": item}))
}
/// Render a `court` create form.
///
/// # Errors
///
/// When there is an issue with rendering the view.
pub fn create(v: &impl ViewRenderer) -> Result<Response> {
format::render().view(v, "court/create.html", data!({}))
}
/// Render a `court` edit form.
///
/// # Errors
///
/// When there is an issue with rendering the view.
pub fn edit(v: &impl ViewRenderer, item: &courts::Model) -> Result<Response> {
format::render().view(v, "court/edit.html", data!({"item": item}))
}

View File

@@ -1 +1,3 @@
pub mod auth;
pub mod court;