M Cargo.lock => Cargo.lock +16 -0
@@ 32,6 32,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
+name = "ascii_utils"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
+
+[[package]]
name = "async-trait"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 328,6 334,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
+name = "fast_chemail"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4"
+dependencies = [
+ "ascii_utils",
+]
+
+[[package]]
name = "fluent"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ 850,6 865,7 @@ dependencies = [
"chrono",
"deadpool-postgres",
"either",
+ "fast_chemail",
"fluent",
"fluent-langneg",
"futures",
M Cargo.toml => Cargo.toml +1 -0
@@ 41,6 41,7 @@ fluent-langneg = "0.13.0"
unic-langid = { version = "0.9.0", features = ["macros"] }
activitystreams = "0.7.0-alpha.3"
activitystreams-ext = "0.1.0-alpha.2"
+fast_chemail = "0.9.6"
[dev-dependencies]
rand = "0.7.3"
A migrations/20200919000846_email/down.sql => migrations/20200919000846_email/down.sql +3 -0
@@ 0,0 1,3 @@
+BEGIN;
+ ALTER TABLE person DROP COLUMN email_address;
+COMMIT;
A migrations/20200919000846_email/up.sql => migrations/20200919000846_email/up.sql +3 -0
@@ 0,0 1,3 @@
+BEGIN;
+ ALTER TABLE person ADD COLUMN email_address TEXT UNIQUE;
+COMMIT;
M openapi/openapi.json => openapi/openapi.json +1 -0
@@ 1161,6 1161,7 @@
"properties": {
"username": {"type": "string"},
"password": {"type": "string"},
+ "email_address": {"type": "string", "format": "email"},
"login": {
"type": "boolean",
"description": "If true, will also create a login token for the new user"
M res/lang/en.ftl => res/lang/en.ftl +1 -0
@@ 19,4 19,5 @@ post_needs_content = Post must contain one of href, content_text, or content_mar
post_not_in_community = That post is not in this community
post_not_yours = That's not your post
root = lotide is running. Note that lotide itself does not include a frontend, and you'll need to install one separately.
+user_email_invalid = Specified email address is invalid
user_name_disallowed_chars = Username contains disallowed characters
M src/routes/api/users.rs => src/routes/api/users.rs +13 -2
@@ 97,6 97,8 @@ async fn route_unstable_users_create(
struct UsersCreateBody<'a> {
username: Cow<'a, str>,
password: String,
+ email_address: Option<Cow<'a, str>>,
+
#[serde(default)]
login: bool,
}
@@ 112,6 114,15 @@ async fn route_unstable_users_create(
}
}
+ if let Some(email) = &body.email_address {
+ if !fast_chemail::is_valid_email(email) {
+ return Err(crate::Error::UserError(crate::simple_response(
+ hyper::StatusCode::BAD_REQUEST,
+ lang.tr("user_email_invalid", None).into_owned(),
+ )));
+ }
+ }
+
let req_password = body.password;
let passhash =
tokio::task::spawn_blocking(move || bcrypt::hash(req_password, bcrypt::DEFAULT_COST))
@@ 136,8 147,8 @@ async fn route_unstable_users_create(
}
})?;
let row = trans.query_one(
- "INSERT INTO person (username, local, created_local, passhash) VALUES ($1, TRUE, current_timestamp, $2) RETURNING id",
- &[&body.username, &passhash],
+ "INSERT INTO person (username, local, created_local, passhash, email_address) VALUES ($1, TRUE, current_timestamp, $2, $3) RETURNING id",
+ &[&body.username, &passhash, &body.email_address],
).await?;
trans.commit().await?;