loco straucture
Some checks failed
CI / Check Style (push) Has been cancelled
CI / Run Clippy (push) Has been cancelled
CI / Run Tests (push) Has been cancelled

This commit is contained in:
Priec
2026-06-16 23:40:53 +02:00
parent 9ce07e8c23
commit af930b79bb
42 changed files with 97 additions and 102 deletions

View File

@@ -1 +0,0 @@
pub mod users;

View File

@@ -1 +0,0 @@
pub mod audit_logs;

View File

@@ -16,8 +16,14 @@ use std::{path::Path, sync::Arc};
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::{ use crate::{
account, admin, cart, checkout, home, i18n, initializers, media, controllers::{
models::_entities::users, shop, tasks, workers::downloader::DownloadWorker, admin_categories, admin_dashboard, admin_form, admin_login, admin_orders,
admin_products, admin_shipping, auth, cart, checkout, home, i18n, media, shop,
},
initializers,
models::_entities::users,
tasks,
workers::downloader::DownloadWorker,
}; };
pub struct App; pub struct App;
@@ -66,16 +72,16 @@ impl Hooks for App {
.add_route(cart::routes()) .add_route(cart::routes())
.add_route(checkout::routes()) .add_route(checkout::routes())
// cross-cutting // cross-cutting
.add_route(account::routes()) .add_route(auth::routes())
.add_route(i18n::routes()) .add_route(i18n::routes())
.add_route(media::routes()) .add_route(media::routes())
// admin // admin
.add_route(admin::routes()) .add_route(admin_dashboard::routes())
.add_route(admin::login::routes()) .add_route(admin_login::routes())
.add_route(admin::products::routes()) .add_route(admin_products::routes())
.add_route(admin::categories::routes()) .add_route(admin_categories::routes())
.add_route(admin::orders::routes()) .add_route(admin_orders::routes())
.add_route(admin::shipping::routes()) .add_route(admin_shipping::routes())
} }
async fn after_context(ctx: AppContext) -> Result<AppContext> { async fn after_context(ctx: AppContext) -> Result<AppContext> {

View File

@@ -1,3 +0,0 @@
pub mod order_items;
pub mod orders;
pub mod shipping_methods;

View File

@@ -11,14 +11,16 @@ use sea_orm::{
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
admin::form::{read_multipart_form, store_image, MultipartForm}, controllers::{
i18n::current_lang, admin_form::{read_multipart_form, store_image, MultipartForm},
media::IMAGE_MAX_BYTES, i18n::current_lang,
media::IMAGE_MAX_BYTES,
},
shared::{ shared::{
guard, guard,
slug::{slugify, unique_slug}, slug::{slugify, unique_slug},
}, },
shop::models::{categories, products}, models::{categories, products},
}; };
async fn category_by_id(ctx: &AppContext, id: i32) -> Result<categories::Model> { async fn category_by_id(ctx: &AppContext, id: i32) -> Result<categories::Model> {

View File

@@ -1,13 +1,4 @@
//! Admin area. Each surface lives in its own submodule; this module holds the //! Admin dashboard (HTML home + JSON stats).
//! dashboard (HTML home + JSON stats) and is the entry point for admin routes.
pub mod categories;
pub mod form;
pub mod login;
pub mod models;
pub mod orders;
pub mod products;
pub mod shipping;
use axum_extra::extract::cookie::CookieJar; use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*; use loco_rs::prelude::*;
@@ -15,7 +6,7 @@ use sea_orm::{EntityTrait, PaginatorTrait};
use serde::Serialize; use serde::Serialize;
use serde_json::json; use serde_json::json;
use crate::{i18n::current_lang, models::_entities, shared::guard}; use crate::{controllers::i18n::current_lang, models::_entities, shared::guard};
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
struct DashboardResponse { struct DashboardResponse {

View File

@@ -9,7 +9,7 @@ use std::collections::HashMap;
use axum::extract::Multipart; use axum::extract::Multipart;
use loco_rs::prelude::*; use loco_rs::prelude::*;
use crate::media::{detect_image_extension, store_upload, IMAGE_MAX_BYTES, IMAGE_STORAGE_DIR}; use crate::controllers::media::{detect_image_extension, store_upload, IMAGE_MAX_BYTES, IMAGE_STORAGE_DIR};
fn normalize_empty(value: Option<String>) -> Option<String> { fn normalize_empty(value: Option<String>) -> Option<String> {
value.and_then(|value| { value.and_then(|value| {

View File

@@ -6,8 +6,9 @@ use loco_rs::prelude::*;
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
account::{self as auth_controller, models::users::{self, LoginParams}}, controllers::auth as auth_controller,
i18n::current_lang, models::users::{self, LoginParams},
controllers::i18n::current_lang,
shared::guard, shared::guard,
}; };

View File

@@ -7,11 +7,9 @@ use serde::Deserialize;
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
checkout::{ models::{order_items, orders},
models::{order_items, orders}, views::checkout as view,
view, controllers::i18n::current_lang,
},
i18n::current_lang,
shared::{guard, settings}, shared::{guard, settings},
}; };

View File

@@ -10,18 +10,18 @@ use sea_orm::{
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
admin::form::{read_multipart_form, store_image, MultipartForm}, controllers::{
i18n::current_lang, admin_form::{read_multipart_form, store_image, MultipartForm},
media::IMAGE_MAX_BYTES, i18n::current_lang,
media::IMAGE_MAX_BYTES,
},
shared::{ shared::{
guard, guard,
money::parse_price_to_cents, money::parse_price_to_cents,
slug::{slugify, unique_slug}, slug::{slugify, unique_slug},
}, },
shop::{ models::{categories, product_images, products},
models::{categories, product_images, products}, views::shop as view,
view,
},
}; };
async fn product_by_id(ctx: &AppContext, id: i32) -> Result<products::Model> { async fn product_by_id(ctx: &AppContext, id: i32) -> Result<products::Model> {

View File

@@ -7,8 +7,8 @@ use serde::Deserialize;
use serde_json::json; use serde_json::json;
use crate::{ use crate::{
checkout::models::shipping_methods, models::shipping_methods,
i18n::current_lang, controllers::i18n::current_lang,
shared::{ shared::{
guard, guard,
money::{format_price, parse_price_to_cents}, money::{format_price, parse_price_to_cents},

View File

@@ -1,9 +1,6 @@
pub mod models;
pub mod view;
use crate::{ use crate::{
account::models::users::{self, LoginParams, RegisterParams}, models::users::{self, LoginParams, RegisterParams},
account::view::{CurrentResponse, LoginResponse}, views::auth::{CurrentResponse, LoginResponse},
mailers::auth::AuthMailer, mailers::auth::AuthMailer,
shared::guard::is_admin, shared::guard::is_admin,
}; };

View File

@@ -1,4 +1,4 @@
use crate::{i18n::current_lang, shared::money::format_price, shop::models::products}; use crate::{controllers::i18n::current_lang, shared::money::format_price, models::products};
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite}; use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
use loco_rs::prelude::*; use loco_rs::prelude::*;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};

View File

@@ -8,18 +8,12 @@ use serde::Deserialize;
use serde_json::json; use serde_json::json;
use time::Duration as TimeDuration; use time::Duration as TimeDuration;
pub mod models;
pub mod view;
use crate::{ use crate::{
cart::{resolve_cart, CART_COOKIE}, controllers::cart::{resolve_cart, CART_COOKIE},
checkout::models::{ models::{order_items, orders, shipping_methods},
order_items, controllers::i18n::current_lang,
orders::{self, Checkout},
shipping_methods,
},
i18n::current_lang,
shared::{money::format_price, settings}, shared::{money::format_price, settings},
views::checkout as view,
}; };
const PAYMENT_METHODS: [&str; 2] = ["cod", "bank_transfer"]; const PAYMENT_METHODS: [&str; 2] = ["cod", "bank_transfer"];
@@ -145,7 +139,7 @@ async fn place_order(
let order = orders::place( let order = orders::place(
&ctx, &ctx,
&valid, &valid,
Checkout { orders::Checkout {
email, email,
customer_name: trimmed(&form.customer_name), customer_name: trimmed(&form.customer_name),
address: trimmed(&form.address), address: trimmed(&form.address),

View File

@@ -4,7 +4,7 @@ use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*; use loco_rs::prelude::*;
use serde_json::json; use serde_json::json;
use crate::{i18n::current_lang, shared::guard, shop}; use crate::{controllers::i18n::current_lang, shared::guard, controllers::shop};
#[debug_handler] #[debug_handler]
async fn index( async fn index(

14
src/controllers/mod.rs Normal file
View File

@@ -0,0 +1,14 @@
pub mod auth;
pub mod admin_categories;
pub mod admin_dashboard;
pub mod admin_form;
pub mod admin_login;
pub mod admin_orders;
pub mod admin_products;
pub mod admin_shipping;
pub mod cart;
pub mod checkout;
pub mod home;
pub mod i18n;
pub mod media;
pub mod shop;

View File

@@ -6,13 +6,11 @@ use loco_rs::prelude::*;
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, Set}; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter, QueryOrder, QuerySelect, Set};
use serde_json::json; use serde_json::json;
pub mod models;
pub mod view;
use crate::{ use crate::{
i18n::current_lang, controllers::i18n::current_lang,
shared::guard, shared::guard,
shop::models::{categories, product_images, products}, models::{categories, product_images, products},
views::shop as view,
}; };
/// Shape a list of products into card rows, loading each one's primary image. /// Shape a list of products into card rows, loading each one's primary image.

View File

@@ -1,7 +1,7 @@
use async_trait::async_trait; use async_trait::async_trait;
use loco_rs::prelude::*; use loco_rs::prelude::*;
use crate::account::models::users::{self, RegisterParams}; use crate::models::users::{self, RegisterParams};
pub struct AdminSeeder; pub struct AdminSeeder;

View File

@@ -1,22 +1,10 @@
pub mod app; pub mod app;
pub mod controllers;
pub mod data; pub mod data;
pub mod initializers; pub mod initializers;
pub mod mailers; pub mod mailers;
pub mod models; pub mod models;
pub mod tasks;
pub mod workers;
// Cross-cutting helpers shared by every feature.
pub mod shared; pub mod shared;
pub mod tasks;
// Feature slices: each owns its routes, handlers, view-shaping and the model pub mod views;
// methods/services specific to it. Generated sea-orm entities stay shared in pub mod workers;
// `models::_entities`.
pub mod account;
pub mod admin;
pub mod cart;
pub mod checkout;
pub mod home;
pub mod i18n;
pub mod media;
pub mod shop;

View File

@@ -4,7 +4,7 @@
use loco_rs::prelude::*; use loco_rs::prelude::*;
use serde_json::json; use serde_json::json;
use crate::account::models::users; use crate::models::users;
static welcome: Dir<'_> = include_dir!("src/mailers/auth/welcome"); static welcome: Dir<'_> = include_dir!("src/mailers/auth/welcome");
static forgot: Dir<'_> = include_dir!("src/mailers/auth/forgot"); static forgot: Dir<'_> = include_dir!("src/mailers/auth/forgot");

View File

@@ -1,7 +1,18 @@
//! Shared data layer: the sea-orm entities generated by `loco generate`. //! Shared data layer: SeaORM entities and their hand-written model extensions.
//! //!
//! These structs cross-reference each other (relations) and are regenerated as //! `_entities/` contains auto-generated SeaORM code (regenerated as a unit).
//! a unit, so they live here centrally. The hand-written model methods, //! The sibling files contain hand-written model impls: ActiveModelBehavior,
//! services and view-shaping that use them live in the feature slices //! finder methods, business logic, and query helpers.
//! (`shop::models`, `checkout::models`, `account::models`, …).
pub mod _entities; pub mod _entities;
pub mod audit_logs;
pub mod categories;
pub mod order_items;
pub mod orders;
pub mod product_images;
pub mod product_product_tags;
pub mod product_tags;
pub mod products;
pub mod shipping_methods;
pub mod users;

View File

@@ -3,8 +3,8 @@
use axum_extra::extract::cookie::CookieJar; use axum_extra::extract::cookie::CookieJar;
use loco_rs::prelude::*; use loco_rs::prelude::*;
use crate::account::models::users; use crate::models::users;
use crate::account::AUTH_COOKIE; use crate::controllers::auth::AUTH_COOKIE;
use crate::shared::settings; use crate::shared::settings;
/// Is `user` the configured admin (settings.admin_email)? /// Is `user` the configured admin (settings.admin_email)?

View File

@@ -1,5 +0,0 @@
pub mod categories;
pub mod product_images;
pub mod product_product_tags;
pub mod product_tags;
pub mod products;

5
src/views/mod.rs Normal file
View File

@@ -0,0 +1,5 @@
//! JSON view-shaping structs for API responses and templates.
pub mod auth;
pub mod checkout;
pub mod shop;

View File

@@ -4,7 +4,7 @@ use loco_rs::testing::prelude::*;
use sea_orm::{ActiveModelTrait, ActiveValue, IntoActiveModel}; use sea_orm::{ActiveModelTrait, ActiveValue, IntoActiveModel};
use serial_test::serial; use serial_test::serial;
use gitara_web::{ use gitara_web::{
account::models::users::{self, Model, RegisterParams}, models::users::{self, Model, RegisterParams},
app::App, app::App,
}; };

View File

@@ -2,7 +2,7 @@ use insta::{assert_debug_snapshot, with_settings};
use loco_rs::testing::prelude::*; use loco_rs::testing::prelude::*;
use rstest::rstest; use rstest::rstest;
use serial_test::serial; use serial_test::serial;
use gitara_web::{account::models::users, app::App}; use gitara_web::{models::users, app::App};
use super::prepare_data; use super::prepare_data;

View File

@@ -1,6 +1,6 @@
use axum::http::{HeaderName, HeaderValue}; use axum::http::{HeaderName, HeaderValue};
use loco_rs::{app::AppContext, TestServer}; use loco_rs::{app::AppContext, TestServer};
use gitara_web::{account::models::users, account::view::LoginResponse}; use gitara_web::{models::users, views::auth::LoginResponse};
const USER_EMAIL: &str = "test@loco.com"; const USER_EMAIL: &str = "test@loco.com";
const USER_PASSWORD: &str = "1234"; const USER_PASSWORD: &str = "1234";