From 98bb0c32c9830b857fa69731c81e60229ba655d5 Mon Sep 17 00:00:00 2001 From: Elad Kaplan Date: Thu, 7 Dec 2023 09:55:11 +0200 Subject: [PATCH 1/3] create a stateless html starter --- .github/workflows/ci-stateless-html.yml | 105 ++++++++++++++++++ starters/stateless_html/.cargo/config.toml | 2 + .../stateless_html/.github/workflows/ci.yaml | 80 +++++++++++++ starters/stateless_html/.gitignore | 16 +++ starters/stateless_html/Cargo.toml | 40 +++++++ starters/stateless_html/README.md | 42 +++++++ .../stateless_html/config/development.yaml | 66 +++++++++++ .../stateless_html/config/production.yaml | 0 starters/stateless_html/config/test.yaml | 66 +++++++++++ starters/stateless_html/generator.yaml | 14 +++ starters/stateless_html/src/app.rs | 30 +++++ starters/stateless_html/src/bin/main.rs | 7 ++ .../stateless_html/src/controllers/main.rs | 20 ++++ .../stateless_html/src/controllers/mod.rs | 1 + starters/stateless_html/src/lib.rs | 6 + starters/stateless_html/src/mailers/auth.rs | 40 +++++++ .../src/mailers/auth/forgot/html.ejs | 8 ++ .../src/mailers/auth/forgot/subject.ejs | 1 + .../src/mailers/auth/forgot/text.ejs | 3 + .../src/mailers/auth/welcome/html.t | 10 ++ .../src/mailers/auth/welcome/subject.t | 1 + .../src/mailers/auth/welcome/text.t | 4 + starters/stateless_html/src/mailers/mod.rs | 1 + starters/stateless_html/src/tasks/example.rs | 24 ++++ starters/stateless_html/src/tasks/mod.rs | 1 + starters/stateless_html/src/views/homepage.t | 78 +++++++++++++ starters/stateless_html/src/views/mod.rs | 1 + .../stateless_html/src/workers/downloader.rs | 27 +++++ starters/stateless_html/src/workers/mod.rs | 1 + starters/stateless_html/tests/mod.rs | 1 + .../stateless_html/tests/requests/homepage.rs | 27 +++++ starters/stateless_html/tests/requests/mod.rs | 1 + .../requests/snapshots/can_get_homepage.snap | 5 + 33 files changed, 729 insertions(+) create mode 100644 .github/workflows/ci-stateless-html.yml create mode 100644 starters/stateless_html/.cargo/config.toml create mode 100644 starters/stateless_html/.github/workflows/ci.yaml create mode 100644 starters/stateless_html/.gitignore create mode 100644 starters/stateless_html/Cargo.toml create mode 100644 starters/stateless_html/README.md create mode 100644 starters/stateless_html/config/development.yaml create mode 100644 starters/stateless_html/config/production.yaml create mode 100644 starters/stateless_html/config/test.yaml create mode 100644 starters/stateless_html/generator.yaml create mode 100644 starters/stateless_html/src/app.rs create mode 100644 starters/stateless_html/src/bin/main.rs create mode 100644 starters/stateless_html/src/controllers/main.rs create mode 100644 starters/stateless_html/src/controllers/mod.rs create mode 100644 starters/stateless_html/src/lib.rs create mode 100644 starters/stateless_html/src/mailers/auth.rs create mode 100644 starters/stateless_html/src/mailers/auth/forgot/html.ejs create mode 100644 starters/stateless_html/src/mailers/auth/forgot/subject.ejs create mode 100644 starters/stateless_html/src/mailers/auth/forgot/text.ejs create mode 100644 starters/stateless_html/src/mailers/auth/welcome/html.t create mode 100644 starters/stateless_html/src/mailers/auth/welcome/subject.t create mode 100644 starters/stateless_html/src/mailers/auth/welcome/text.t create mode 100644 starters/stateless_html/src/mailers/mod.rs create mode 100644 starters/stateless_html/src/tasks/example.rs create mode 100644 starters/stateless_html/src/tasks/mod.rs create mode 100644 starters/stateless_html/src/views/homepage.t create mode 100644 starters/stateless_html/src/views/mod.rs create mode 100644 starters/stateless_html/src/workers/downloader.rs create mode 100644 starters/stateless_html/src/workers/mod.rs create mode 100644 starters/stateless_html/tests/mod.rs create mode 100644 starters/stateless_html/tests/requests/homepage.rs create mode 100644 starters/stateless_html/tests/requests/mod.rs create mode 100644 starters/stateless_html/tests/requests/snapshots/can_get_homepage.snap diff --git a/.github/workflows/ci-stateless-html.yml b/.github/workflows/ci-stateless-html.yml new file mode 100644 index 000000000..64d873127 --- /dev/null +++ b/.github/workflows/ci-stateless-html.yml @@ -0,0 +1,105 @@ +name: STARTER-STATELESS + +on: + push: + branches: + - master + pull_request: + +env: + RUST_TOOLCHAIN: stable + TOOLCHAIN_PROFILE: minimal + +jobs: + rustfmt: + name: Check Style + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + components: rustfmt + - run: cargo fmt --all -- --check + working-directory: ./starters/stateless_html + + clippy: + name: Run Clippy + needs: [rustfmt] + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + - name: Run cargo clippy + run: cargo clippy -- -W clippy::nursery -W clippy::pedantic -W rust-2018-idioms -W rust-2021-compatibility + working-directory: ./starters/stateless_html + + test: + name: Run Tests + needs: [rustfmt, clippy] + runs-on: ubuntu-latest + + permissions: + contents: read + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + - name: Run cargo test + run: cargo test --all-features --all + working-directory: ./starters/stateless_html + + generate_template: + name: Generate Template + needs: [test] + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + - name: Inject slug/short variables + uses: rlespinasse/github-slug-action@v3.x + - name: Generate template + run: | + cargo build --release --features github_ci + RUST_LOG=debug LOCO_CURRENT_REPOSITORY=${{ github.event.pull_request.head.repo.html_url }} LOCO_CI_MODE=true LOCO_APP_NAME=stateless_html_starter LOCO_TEMPLATE=stateless_html LOCO_BRANCH=${{ env.GITHUB_HEAD_REF_SLUG }} ./target/release/loco new + cd stateless_html_starter + echo "Building generate template..." + cargo build --release + echo "Run cargo test on generated template..." + cargo test + working-directory: ./loco-cli diff --git a/starters/stateless_html/.cargo/config.toml b/starters/stateless_html/.cargo/config.toml new file mode 100644 index 000000000..5ebf03388 --- /dev/null +++ b/starters/stateless_html/.cargo/config.toml @@ -0,0 +1,2 @@ +[alias] +loco = "run --" diff --git a/starters/stateless_html/.github/workflows/ci.yaml b/starters/stateless_html/.github/workflows/ci.yaml new file mode 100644 index 000000000..15ee4a6a2 --- /dev/null +++ b/starters/stateless_html/.github/workflows/ci.yaml @@ -0,0 +1,80 @@ +name: CI +on: + push: + branches: + - master + - main + pull_request: + +env: + RUST_TOOLCHAIN: stable + TOOLCHAIN_PROFILE: minimal + +jobs: + rustfmt: + name: Check Style + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + components: rustfmt + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + name: Run Clippy + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-features -- -D warnings -W clippy::pedantic -W clippy::nursery -W rust-2018-idioms + + test: + name: Run Tests + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - name: Checkout the code + uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 + with: + profile: ${{ env.TOOLCHAIN_PROFILE }} + toolchain: ${{ env.RUST_TOOLCHAIN }} + override: true + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + - name: Run cargo test + uses: actions-rs/cargo@v1 + with: + command: test + args: --all-features --all diff --git a/starters/stateless_html/.gitignore b/starters/stateless_html/.gitignore new file mode 100644 index 000000000..5d5402d5c --- /dev/null +++ b/starters/stateless_html/.gitignore @@ -0,0 +1,16 @@ +**/config/local.yaml + +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/starters/stateless_html/Cargo.toml b/starters/stateless_html/Cargo.toml new file mode 100644 index 000000000..c4bcd8919 --- /dev/null +++ b/starters/stateless_html/Cargo.toml @@ -0,0 +1,40 @@ +[workspace] + +[package] +name = "loco_starter_template" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +loco-rs = { path = "../../", default-features = false, features = ["cli"] } +serde = "*" +serde_json = "*" +eyre = "*" +tokio = { version = "1.33.0", default-features = false } +async-trait = "0.1.74" +tracing = "0.1.40" +validator = { version = "*" } + +axum = "0.7.1" +include_dir = "*" +uuid = { version = "*", features = ["v4"] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter", "json"] } +tera = "1.19.1" +cargo_metadata = "0.18.1" + +[[bin]] +name = "loco_starter_template" +path = "src/bin/main.rs" +required-features = [] + +[dev-dependencies] +serial_test = "*" +rstest = "*" +loco-rs = { path = "../../", default-features = false, features = [ + "testing", + "cli", +] } +insta = { version = "*", features = ["redactions", "yaml", "filters"] } diff --git a/starters/stateless_html/README.md b/starters/stateless_html/README.md new file mode 100644 index 000000000..a3657f61a --- /dev/null +++ b/starters/stateless_html/README.md @@ -0,0 +1,42 @@ +# Welcome to Loco :train: + +Loco is a web and API framework running on Rust. + +This is the **Stateless HTML starter** which comes with no database or state dependencies. + +## Quick Start + +Start your app: + +``` +$ cargo loco start +Finished dev [unoptimized + debuginfo] target(s) in 21.63s + Running `target/debug/myapp start` + + : + : + : + +controller/app_routes.rs:203: [Middleware] Adding log trace id + + ▄ ▀ + ▀ ▄ + ▄ ▀ ▄ ▄ ▄▀ + ▄ ▀▄▄ + ▄ ▀ ▀ ▀▄▀█▄ + ▀█▄ +▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄ ▀▀█ + ██████ █████ ███ █████ ███ █████ ███ ▀█ + ██████ █████ ███ █████ ▀▀▀ █████ ███ ▄█▄ + ██████ █████ ███ █████ █████ ███ ████▄ + ██████ █████ ███ █████ ▄▄▄ █████ ███ █████ + ██████ █████ ███ ████ ███ █████ ███ ████▀ + ▀▀▀██▄ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ██▀ + ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ + +started on port 3000 +``` + +## Getting help + +Check out [a quick tour](https://loco.rs/docs/getting-started/tour/) or [the complete guide](https://loco.rs/docs/getting-started/guide/). diff --git a/starters/stateless_html/config/development.yaml b/starters/stateless_html/config/development.yaml new file mode 100644 index 000000000..8d347ce7e --- /dev/null +++ b/starters/stateless_html/config/development.yaml @@ -0,0 +1,66 @@ +# Loco configuration file documentation + +# Application logging configuration +logger: + # Enable or disable logging. + enable: true + # Log level, options: trace, debug, info, warn or error. + level: debug + # Define the logging format. options: compact, pretty or Json + format: compact + # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries + # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. + # override_filter: trace + +# Web server configuration +server: + # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} + port: 3000 + # The UI hostname or IP address that mailers will point to. + host: http://localhost + # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block + middlewares: + # Allows to limit the payload size request. payload that bigger than this file will blocked the request. + limit_payload: + # Enable/Disable the middleware. + enable: true + # the limit size. can be b,kb,kib,mb,mib,gb,gib + body_limit: 5mb + # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. + logger: + # Enable/Disable the middleware. + enable: true + # when your code is panicked, the request still returns 500 status code. + catch_panic: + # Enable/Disable the middleware. + enable: true + # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. + timeout_request: + # Enable/Disable the middleware. + enable: true + # Duration time in milliseconds. + timeout: 5000 + +# Worker Configuration +workers: + # specifies the worker mode. Options: + # - BackgroundQueue - Workers operate asynchronously in the background, processing queued. + # - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed. + # - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities. + mode: BackgroundQueue + +# Mailer Configuration. +mailer: + # SMTP mailer configuration. + smtp: + # Enable/Disable smtp mailer. + enable: true + # SMTP server host. e.x localhost, smtp.gmail.com + host: localhost + # SMTP server port + port: 1025 + # Use secure connection (SSL/TLS). + secure: false + # auth: + # user: + # password: diff --git a/starters/stateless_html/config/production.yaml b/starters/stateless_html/config/production.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/starters/stateless_html/config/test.yaml b/starters/stateless_html/config/test.yaml new file mode 100644 index 000000000..3b6d19590 --- /dev/null +++ b/starters/stateless_html/config/test.yaml @@ -0,0 +1,66 @@ +# Loco configuration file documentation + +# Application logging configuration +logger: + # Enable or disable logging. + enable: false + # Log level, options: trace, debug, info, warn or error. + level: debug + # Define the logging format. options: compact, pretty or Json + format: compact + # By default the logger has filtering only logs that came from your code or logs that came from `loco` framework. to see all third party libraries + # Uncomment the line below to override to see all third party libraries you can enable this config and override the logger filters. + # override_filter: trace + +# Web server configuration +server: + # Port on which the server will listen. the server binding is 0.0.0.0:{PORT} + port: 3000 + # The UI hostname or IP address that mailers will point to. + host: http://localhost + # Out of the box middleware configuration. to disable middleware you can changed the `enable` field to `false` of comment the middleware block + middlewares: + # Allows to limit the payload size request. payload that bigger than this file will blocked the request. + limit_payload: + # Enable/Disable the middleware. + enable: true + # the limit size. can be b,kb,kib,mb,mib,gb,gib + body_limit: 5mb + # Generating a unique request ID and enhancing logging with additional information such as the start and completion of request processing, latency, status code, and other request details. + logger: + # Enable/Disable the middleware. + enable: true + # when your code is panicked, the request still returns 500 status code. + catch_panic: + # Enable/Disable the middleware. + enable: true + # Timeout for incoming requests middleware. requests that take more time from the configuration will cute and 408 status code will returned. + timeout_request: + # Enable/Disable the middleware. + enable: true + # Duration time in milliseconds. + timeout: 5000 + +# Worker Configuration +workers: + # specifies the worker mode. Options: + # - BackgroundQueue - Workers operate asynchronously in the background, processing queued. + # - ForegroundBlocking - Workers operate in the foreground and block until tasks are completed. + # - BackgroundAsync - Workers operate asynchronously in the background, processing tasks with async capabilities. + mode: ForegroundBlocking + +# Mailer Configuration. +mailer: + # SMTP mailer configuration. + smtp: + # Enable/Disable smtp mailer. + enable: true + # SMTP server host. e.x localhost, smtp.gmail.com + host: localhost + # SMTP server port + port: 1025 + # Use secure connection (SSL/TLS). + secure: false + # auth: + # user: + # password: diff --git a/starters/stateless_html/generator.yaml b/starters/stateless_html/generator.yaml new file mode 100644 index 000000000..15643c168 --- /dev/null +++ b/starters/stateless_html/generator.yaml @@ -0,0 +1,14 @@ +--- +description: Stateless HTML (minimal, no db) +rules: + - pattern: loco-rs = \{ path = +.(../../)+. + skip_in_ci: true + kind: loco-rs = { version = "*" + file_patterns: + - Cargo.toml + - pattern: loco_starter_template + kind: LibName + file_patterns: + - rs + - toml + - trycmd diff --git a/starters/stateless_html/src/app.rs b/starters/stateless_html/src/app.rs new file mode 100644 index 000000000..5356b5d8f --- /dev/null +++ b/starters/stateless_html/src/app.rs @@ -0,0 +1,30 @@ +use async_trait::async_trait; +use loco_rs::{ + app::{AppContext, Hooks}, + controller::AppRoutes, + task::Tasks, + worker::{AppWorker, Processor}, +}; + +use crate::{controllers, tasks, workers::downloader::DownloadWorker}; + +pub struct App; +#[async_trait] +impl Hooks for App { + fn app_name() -> &'static str { + env!("CARGO_CRATE_NAME") + } + + fn routes() -> AppRoutes { + AppRoutes::with_default_routes().add_route(controllers::main::routes()) + // .fallback(controllers::not_found::handler_not_found) + } + + fn connect_workers<'a>(p: &'a mut Processor, ctx: &'a AppContext) { + p.register(DownloadWorker::build(ctx)); + } + + fn register_tasks(tasks: &mut Tasks) { + tasks.register(tasks::example::ExpReport); + } +} diff --git a/starters/stateless_html/src/bin/main.rs b/starters/stateless_html/src/bin/main.rs new file mode 100644 index 000000000..f7f877678 --- /dev/null +++ b/starters/stateless_html/src/bin/main.rs @@ -0,0 +1,7 @@ +use loco_rs::cli; +use loco_starter_template::app::App; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + cli::main::().await +} diff --git a/starters/stateless_html/src/controllers/main.rs b/starters/stateless_html/src/controllers/main.rs new file mode 100644 index 000000000..7a83a9a3e --- /dev/null +++ b/starters/stateless_html/src/controllers/main.rs @@ -0,0 +1,20 @@ +use axum::{extract::State, response::Html, routing::get}; +use loco_rs::{ + app::AppContext, + controller::{format, Routes}, + Result, +}; +use tera::Tera; + +const HOMEPAGE_T: &str = include_str!("../views/homepage.t"); + +async fn index(State(ctx): State) -> Result> { + let mut context = tera::Context::new(); + context.insert("environment", &ctx.environment.to_string()); + + format::html(&Tera::one_off(HOMEPAGE_T, &context, true)?) +} + +pub fn routes() -> Routes { + Routes::new().add("/", get(index)) +} diff --git a/starters/stateless_html/src/controllers/mod.rs b/starters/stateless_html/src/controllers/mod.rs new file mode 100644 index 000000000..2a043412b --- /dev/null +++ b/starters/stateless_html/src/controllers/mod.rs @@ -0,0 +1 @@ +pub mod main; diff --git a/starters/stateless_html/src/lib.rs b/starters/stateless_html/src/lib.rs new file mode 100644 index 000000000..c365fecc7 --- /dev/null +++ b/starters/stateless_html/src/lib.rs @@ -0,0 +1,6 @@ +pub mod app; +pub mod controllers; +pub mod mailers; +pub mod tasks; +pub mod views; +pub mod workers; diff --git a/starters/stateless_html/src/mailers/auth.rs b/starters/stateless_html/src/mailers/auth.rs new file mode 100644 index 000000000..328b7f6f1 --- /dev/null +++ b/starters/stateless_html/src/mailers/auth.rs @@ -0,0 +1,40 @@ +// auth mailer +#![allow(non_upper_case_globals)] + +use include_dir::{include_dir, Dir}; +use loco_rs::{ + app::AppContext, + mailer::{Args, Mailer}, + Result, +}; +use serde_json::json; + +static welcome: Dir<'_> = include_dir!("src/mailers/auth/welcome"); +// #[derive(Mailer)] // -- disabled for faster build speed. it works. but lets +// move on for now. + +#[allow(clippy::module_name_repetitions)] +pub struct AuthMailer {} +impl Mailer for AuthMailer {} +impl AuthMailer { + /// Sending welcome email the the given user + /// + /// # Errors + /// + /// When email sending is failed + pub async fn send_welcome(ctx: &AppContext, _user_id: &str) -> Result<()> { + Self::mail_template( + ctx, + &welcome, + Args { + to: "foo@example.com".to_string(), + locals: json!({ + "name": "joe" + }), + ..Default::default() + }, + ) + .await?; + Ok(()) + } +} diff --git a/starters/stateless_html/src/mailers/auth/forgot/html.ejs b/starters/stateless_html/src/mailers/auth/forgot/html.ejs new file mode 100644 index 000000000..9eecc95d3 --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/forgot/html.ejs @@ -0,0 +1,8 @@ +; + + + You can + reset your password + + + diff --git a/starters/stateless_html/src/mailers/auth/forgot/subject.ejs b/starters/stateless_html/src/mailers/auth/forgot/subject.ejs new file mode 100644 index 000000000..4938df1e3 --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/forgot/subject.ejs @@ -0,0 +1 @@ +Your reset password link diff --git a/starters/stateless_html/src/mailers/auth/forgot/text.ejs b/starters/stateless_html/src/mailers/auth/forgot/text.ejs new file mode 100644 index 000000000..faa520ab4 --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/forgot/text.ejs @@ -0,0 +1,3 @@ +Reset your password with this link: + +http://localhost/reset/<%= resetToken %> diff --git a/starters/stateless_html/src/mailers/auth/welcome/html.t b/starters/stateless_html/src/mailers/auth/welcome/html.t new file mode 100644 index 000000000..e0eee75ea --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/welcome/html.t @@ -0,0 +1,10 @@ +; + + + You can{' '} + + verify your account + + + + diff --git a/starters/stateless_html/src/mailers/auth/welcome/subject.t b/starters/stateless_html/src/mailers/auth/welcome/subject.t new file mode 100644 index 000000000..122d0922b --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/welcome/subject.t @@ -0,0 +1 @@ +Welcome <%= name %> diff --git a/starters/stateless_html/src/mailers/auth/welcome/text.t b/starters/stateless_html/src/mailers/auth/welcome/text.t new file mode 100644 index 000000000..9ef614dd4 --- /dev/null +++ b/starters/stateless_html/src/mailers/auth/welcome/text.t @@ -0,0 +1,4 @@ +Welcome <%= name %>, you can now log in. + Verify your account with the link below: + + http://localhost/verify/<%= verifyToken %> diff --git a/starters/stateless_html/src/mailers/mod.rs b/starters/stateless_html/src/mailers/mod.rs new file mode 100644 index 000000000..0e4a05d59 --- /dev/null +++ b/starters/stateless_html/src/mailers/mod.rs @@ -0,0 +1 @@ +pub mod auth; diff --git a/starters/stateless_html/src/tasks/example.rs b/starters/stateless_html/src/tasks/example.rs new file mode 100644 index 000000000..0c9dbc782 --- /dev/null +++ b/starters/stateless_html/src/tasks/example.rs @@ -0,0 +1,24 @@ +use std::collections::BTreeMap; + +use async_trait::async_trait; +use loco_rs::{ + app::AppContext, + task::{Task, TaskInfo}, + Result, +}; + +pub struct ExpReport; +#[async_trait] +impl Task for ExpReport { + fn task(&self) -> TaskInfo { + TaskInfo { + name: "example".to_string(), + detail: "output a example task".to_string(), + } + } + async fn run(&self, _app_context: &AppContext, _vars: &BTreeMap) -> Result<()> { + println!("example task executed"); + + Ok(()) + } +} diff --git a/starters/stateless_html/src/tasks/mod.rs b/starters/stateless_html/src/tasks/mod.rs new file mode 100644 index 000000000..d4d8a94c8 --- /dev/null +++ b/starters/stateless_html/src/tasks/mod.rs @@ -0,0 +1 @@ +pub mod example; diff --git a/starters/stateless_html/src/views/homepage.t b/starters/stateless_html/src/views/homepage.t new file mode 100644 index 000000000..4304396ba --- /dev/null +++ b/starters/stateless_html/src/views/homepage.t @@ -0,0 +1,78 @@ +{% set environment = environment | capitalize -%} + + + + + Loco website + + + + + + + + + Welcome to Logo website +
+ +
+ loco.rs + +
    +
  • Environment: + {{environment}} +
  • + +
+ + + \ No newline at end of file diff --git a/starters/stateless_html/src/views/mod.rs b/starters/stateless_html/src/views/mod.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/starters/stateless_html/src/views/mod.rs @@ -0,0 +1 @@ + diff --git a/starters/stateless_html/src/workers/downloader.rs b/starters/stateless_html/src/workers/downloader.rs new file mode 100644 index 000000000..5b5df9aac --- /dev/null +++ b/starters/stateless_html/src/workers/downloader.rs @@ -0,0 +1,27 @@ +use async_trait::async_trait; +use loco_rs::{ + app::AppContext, + worker::{AppWorker, Result, Worker}, +}; +use serde::{Deserialize, Serialize}; + +pub struct DownloadWorker { + pub ctx: AppContext, +} + +#[derive(Deserialize, Debug, Serialize)] +pub struct DownloadWorkerArgs {} + +impl AppWorker for DownloadWorker { + fn build(ctx: &AppContext) -> Self { + Self { ctx: ctx.clone() } + } +} + +#[async_trait] +impl Worker for DownloadWorker { + async fn perform(&self, _args: DownloadWorkerArgs) -> Result<()> { + println!("Download worker started"); + Ok(()) + } +} diff --git a/starters/stateless_html/src/workers/mod.rs b/starters/stateless_html/src/workers/mod.rs new file mode 100644 index 000000000..acb5733da --- /dev/null +++ b/starters/stateless_html/src/workers/mod.rs @@ -0,0 +1 @@ +pub mod downloader; diff --git a/starters/stateless_html/tests/mod.rs b/starters/stateless_html/tests/mod.rs new file mode 100644 index 000000000..c2e46cdd7 --- /dev/null +++ b/starters/stateless_html/tests/mod.rs @@ -0,0 +1 @@ +mod requests; diff --git a/starters/stateless_html/tests/requests/homepage.rs b/starters/stateless_html/tests/requests/homepage.rs new file mode 100644 index 000000000..65a902916 --- /dev/null +++ b/starters/stateless_html/tests/requests/homepage.rs @@ -0,0 +1,27 @@ +use insta::assert_debug_snapshot; +use loco_rs::testing; +use loco_starter_template::app::App; +use serial_test::serial; + +// TODO: see how to dedup / extract this to app-local test utils +// not to framework, because that would require a runtime dep on insta +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 can_get_homepage() { + testing::request::(|request, _ctx| async move { + configure_insta!(); + let response = request.get("/").await; + + assert_eq!(response.status_code(), 200); + assert_debug_snapshot!(response.text()); + }) + .await; +} diff --git a/starters/stateless_html/tests/requests/mod.rs b/starters/stateless_html/tests/requests/mod.rs new file mode 100644 index 000000000..8c4ff324e --- /dev/null +++ b/starters/stateless_html/tests/requests/mod.rs @@ -0,0 +1 @@ +mod homepage; diff --git a/starters/stateless_html/tests/requests/snapshots/can_get_homepage.snap b/starters/stateless_html/tests/requests/snapshots/can_get_homepage.snap new file mode 100644 index 000000000..fe8f77b50 --- /dev/null +++ b/starters/stateless_html/tests/requests/snapshots/can_get_homepage.snap @@ -0,0 +1,5 @@ +--- +source: tests/requests/homepage.rs +expression: response.text() +--- +"\n\n\n\n Loco website\n \n \n \n\n \n\n\n \n Welcome to Logo website \n
\n \n
\n loco.rs\n\n
    \n
  • Environment:\n Test\n
  • \n \n
\n\n\n" From db6a90a4025571454977cadb099b97e803be0f0f Mon Sep 17 00:00:00 2001 From: Elad Kaplan Date: Thu, 7 Dec 2023 10:22:30 +0200 Subject: [PATCH 2/3] some chagnes --- src/controller/format.rs | 2 +- starters/stateless_html/src/views/homepage.t | 2 +- .../tests/requests/snapshots/can_get_homepage.snap | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controller/format.rs b/src/controller/format.rs index e9d7fe42d..8b65544f7 100644 --- a/src/controller/format.rs +++ b/src/controller/format.rs @@ -106,7 +106,7 @@ pub fn json(t: T) -> Result> { /// controller::format, /// Result, /// }; -/// use axum::Html; +/// use axum::response::Html; /// /// async fn endpoint() -> Result> { /// format::html("hello, world") diff --git a/starters/stateless_html/src/views/homepage.t b/starters/stateless_html/src/views/homepage.t index 4304396ba..ad3f2fd35 100644 --- a/starters/stateless_html/src/views/homepage.t +++ b/starters/stateless_html/src/views/homepage.t @@ -56,7 +56,7 @@ - Welcome to Logo website + Welcome to Loco website