Rewrite README + use lettre crate to validate email address instead of regex
This commit is contained in:
parent
67e13d9074
commit
65489e7692
8 changed files with 62 additions and 85 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -440,7 +440,6 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
88
README.md
88
README.md
|
|
@ -1,59 +1,59 @@
|
||||||
# Use cases
|
|
||||||
|
|
||||||
## Create a recipe
|
|
||||||
|
|
||||||
To create a recipe the user must have an account.
|
|
||||||
|
|
||||||
* The user
|
|
||||||
(A group is automatically created)
|
|
||||||
|
|
||||||
## Create a groupe
|
|
||||||
|
|
||||||
## Move a group
|
|
||||||
|
|
||||||
## Delete a group
|
|
||||||
|
|
||||||
## Create a step
|
|
||||||
|
|
||||||
## Move a step
|
|
||||||
|
|
||||||
## Delete a step
|
|
||||||
|
|
||||||
# Technical
|
# Technical
|
||||||
|
|
||||||
## Cross-compilation on Windows 11
|
|
||||||
|
|
||||||
The toolchain for Raspberry Pi 64 bits is available here: https://gnutoolchains.com/raspberry64/
|
|
||||||
|
|
||||||
## How to install service on RPI Zero
|
|
||||||
|
|
||||||
1. Copy doc/recipes.service to /lib/systemd/system
|
|
||||||
2. Enabled it: #> systemctl enable recipes
|
|
||||||
|
|
||||||
## Backend
|
## Backend
|
||||||
|
|
||||||
Autoreload: https://actix.rs/docs/autoreload/
|
### Launch Axum
|
||||||
|
|
||||||
### Frontend
|
In directory '/backend' type:
|
||||||
|
$> cargo run
|
||||||
|
|
||||||
## WebAssembly
|
Then browse http://127.0.0.1:8082 (You need to compile the wasm file first, see section 'Frontend')
|
||||||
|
|
||||||
'frontend' project needs some tools to generate the WebAssembly stuff. Everything is explained here: https://rustwasm.github.io/wasm-bindgen/examples/hello-world.html
|
At first launch the configuration file '/backend/conf.ron' is created. It contains the port the server will listen to and information about the SMTP server which will be used to send email when a user sign up or change its password.
|
||||||
TODO MVC Example:
|
|
||||||
https://github.com/rustwasm/wasm-bindgen/tree/main/examples/todomvc -> https://rustwasm.github.io/wasm-bindgen/exbuild/todomvc/#/
|
|
||||||
|
|
||||||
Javascript bundler: https://rspack.dev/
|
### Autoreload
|
||||||
|
|
||||||
To compile run 'wasm-pack build' in 'frontend' directory
|
First install cargo watch:
|
||||||
To launch node run 'npm run start' in 'frontend/www' directory
|
$> cargo install cargo-watch
|
||||||
|
|
||||||
## Useful URLs
|
In directory '/backend' type:
|
||||||
|
$> cargo watch -x run
|
||||||
* Rust patterns : https://github.com/rust-unofficial/patterns/tree/master/patterns
|
|
||||||
* Node install: https://nodejs.org/en/download/
|
|
||||||
|
|
||||||
|
|
||||||
# Tools
|
## Frontend
|
||||||
|
|
||||||
|
### Tools needed
|
||||||
|
|
||||||
|
nushell: https://www.nushell.sh/
|
||||||
|
wasm-pack: https://github.com/rustwasm/wasm-pack
|
||||||
|
wasm-opt: $> cargo install wasm-opt
|
||||||
|
|
||||||
|
### Compilation
|
||||||
|
|
||||||
|
In directory '/frontend' type:
|
||||||
|
$> nu deploy.nu
|
||||||
|
|
||||||
|
It will create the '/frontend/pkg' directory and copy the wasm file into '/backend/static'.
|
||||||
|
You can now refresh your browser to reload the wasm file.
|
||||||
|
|
||||||
|
# How-to
|
||||||
|
|
||||||
|
## How to install service on a Linux server
|
||||||
|
|
||||||
|
As root:
|
||||||
|
|
||||||
|
1. Copy '/doc/recipes.service' to '/lib/systemd/system/'
|
||||||
|
2. Enabled it: #> systemctl enable recipes
|
||||||
|
3. Launch it: #> systemctl start recipes
|
||||||
|
|
||||||
|
# Useful URLs
|
||||||
|
|
||||||
|
* Rust patterns : https://github.com/rust-unofficial/patterns
|
||||||
|
* Rust cheat Sheet: https://cheats.rs/
|
||||||
|
|
||||||
|
|
||||||
|
# Useful tools
|
||||||
|
|
||||||
Benchmarking: https://crates.io/crates/oha
|
Benchmarking: https://crates.io/crates/oha
|
||||||
HTTP API tool: https://www.usebruno.com/
|
HTTP API tool: https://www.usebruno.com/
|
||||||
|
GUI Database client: https://dbeaver.io/
|
||||||
|
|
|
||||||
10
TODO.md
10
TODO.md
|
|
@ -1,14 +1,22 @@
|
||||||
|
* FIX: when the event blur is triggered when changing page, the async process doesn't finish all the time
|
||||||
* Check position of message error in profile/sign in/sign up with flex grid layout
|
* Check position of message error in profile/sign in/sign up with flex grid layout
|
||||||
* Define the UI (mockups).
|
* Define the UI (mockups).
|
||||||
* Two CSS: one for desktop and one for mobile
|
* Two CSS: one for desktop and one for mobile
|
||||||
* Use CSS flex/grid to define a good design/layout
|
* Use CSS flex/grid to define a good design/layout
|
||||||
* Drag and drop of steps and groups to define their order
|
* CSS for toast and modal dialog
|
||||||
* Make a search page
|
* Make a search page
|
||||||
|
Use FTS5:
|
||||||
|
https://sqlite.org/fts5.html
|
||||||
|
https://www.sqlitetutorial.net/sqlite-full-text-search/
|
||||||
* Use of markdown for some field (how to add markdown as rinja filter?)
|
* Use of markdown for some field (how to add markdown as rinja filter?)
|
||||||
* Quick search left panel by tags ?
|
* Quick search left panel by tags ?
|
||||||
* Make the home page: Define what to display to the user
|
* Make the home page: Define what to display to the user
|
||||||
* Show existing tags when editing a recipe
|
* Show existing tags when editing a recipe
|
||||||
|
|
||||||
|
[ok] Drag and drop of steps and groups to define their order
|
||||||
|
[ok] Force tags in lowercase
|
||||||
|
[ok] Remove the given language to recipe_edit and replace it by tr (like the header)
|
||||||
|
[ok] List only recipe of current language
|
||||||
[ok] Add support to translations.
|
[ok] Add support to translations.
|
||||||
* Make a Text database (a bit like d-lan.net) and think about translation.
|
* Make a Text database (a bit like d-lan.net) and think about translation.
|
||||||
* The language is stored in cookie or in user profile if the user is connected
|
* The language is stored in cookie or in user profile if the user is connected
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use axum_extra::extract::{
|
||||||
Host,
|
Host,
|
||||||
};
|
};
|
||||||
use chrono::Duration;
|
use chrono::Duration;
|
||||||
|
use lettre::Address;
|
||||||
use rinja::Template;
|
use rinja::Template;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{event, Level};
|
use tracing::{event, Level};
|
||||||
|
|
@ -109,9 +110,7 @@ pub async fn sign_up_post(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation of email and password.
|
// Validation of email and password.
|
||||||
if let common::utils::EmailValidation::NotValid =
|
if form_data.email.parse::<Address>().is_err() {
|
||||||
common::utils::validate_email(&form_data.email)
|
|
||||||
{
|
|
||||||
return error_response(SignUpError::InvalidEmail, &form_data, user, tr);
|
return error_response(SignUpError::InvalidEmail, &form_data, user, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,9 +430,7 @@ pub async fn ask_reset_password_post(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation of email.
|
// Validation of email.
|
||||||
if let common::utils::EmailValidation::NotValid =
|
if form_data.email.parse::<Address>().is_err() {
|
||||||
common::utils::validate_email(&form_data.email)
|
|
||||||
{
|
|
||||||
return error_response(
|
return error_response(
|
||||||
AskResetPasswordError::InvalidEmail,
|
AskResetPasswordError::InvalidEmail,
|
||||||
&form_data.email,
|
&form_data.email,
|
||||||
|
|
@ -721,9 +718,7 @@ pub async fn edit_user_post(
|
||||||
.into_response())
|
.into_response())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let common::utils::EmailValidation::NotValid =
|
if form_data.email.parse::<Address>().is_err() {
|
||||||
common::utils::validate_email(&form_data.email)
|
|
||||||
{
|
|
||||||
return error_response(ProfileUpdateError::InvalidEmail, &form_data, user, tr);
|
return error_response(ProfileUpdateError::InvalidEmail, &form_data, user, tr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,5 @@ authors = ["Grégory Burri <greg.burri@gmail.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = "1"
|
|
||||||
|
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,5 @@
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
use crate::consts;
|
use crate::consts;
|
||||||
|
|
||||||
pub enum EmailValidation {
|
|
||||||
Ok,
|
|
||||||
NotValid,
|
|
||||||
}
|
|
||||||
|
|
||||||
static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
|
||||||
Regex::new(
|
|
||||||
r"^([a-z0-9_+]([a-z0-9_+.]*[a-z0-9_+])?)@([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6})",
|
|
||||||
)
|
|
||||||
.expect("Error parsing email regex")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub fn validate_email(email: &str) -> EmailValidation {
|
|
||||||
if EMAIL_REGEX.is_match(email) {
|
|
||||||
EmailValidation::Ok
|
|
||||||
} else {
|
|
||||||
EmailValidation::NotValid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum PasswordValidation {
|
pub enum PasswordValidation {
|
||||||
Ok,
|
Ok,
|
||||||
TooShort,
|
TooShort,
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,7 @@ gloo = "0.11"
|
||||||
# code size when deploying.
|
# code size when deploying.
|
||||||
console_error_panic_hook = { version = "0.1", optional = true }
|
console_error_panic_hook = { version = "0.1", optional = true }
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.release]
|
# wasm-opt is used by default: https://docs.rs/wasm-opt/latest/wasm_opt/
|
||||||
wasm-opt = false
|
# Uncomment the following lines to disable it.
|
||||||
|
# [package.metadata.wasm-pack.profile.release]
|
||||||
|
# wasm-opt = false
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{cell::RefCell, rc, sync::Mutex};
|
use std::{cell::RefCell, rc, sync::Mutex};
|
||||||
|
|
||||||
use gloo::{
|
use gloo::{
|
||||||
console::log,
|
|
||||||
events::{EventListener, EventListenerOptions},
|
events::{EventListener, EventListenerOptions},
|
||||||
net::http::Request,
|
net::http::Request,
|
||||||
utils::{document, window},
|
utils::{document, window},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue