summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2022-09-03 10:10:20 +0000
committerSanto Cariotti <santo@dcariotti.me>2022-09-03 10:10:20 +0000
commit2c6434e0b89e93ab6bdddb28bcd059b48638cb0d (patch)
tree34844dc8d86780d25261c9082cf715226696c6ab
parent6cda1b704d1c38fc116e59a2a206c2adebfb6d4d (diff)
Users has username and use it for login
-rw-r--r--Cargo.lock42
-rw-r--r--migrations/20220822142548_add-users-table.sql6
-rw-r--r--migrations/20220903093057_add-users-table.sql7
-rw-r--r--src/main.rs2
-rw-r--r--src/models/auth.rs7
-rw-r--r--src/models/user.rs33
-rw-r--r--src/routes/auth.rs10
-rw-r--r--src/routes/user.rs4
8 files changed, 64 insertions, 47 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5fc4076..18a84e2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -713,27 +713,6 @@ dependencies = [
]
[[package]]
-name = "verden"
-version = "0.1.0"
-dependencies = [
- "async-trait",
- "axum",
- "chrono",
- "http-body",
- "jsonwebtoken",
- "once_cell",
- "serde",
- "serde_json",
- "sha256",
- "sqlx",
- "tokio",
- "tower-http",
- "tracing",
- "tracing-subscriber",
- "validator",
-]
-
-[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1790,6 +1769,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
+name = "verden"
+version = "0.1.0"
+dependencies = [
+ "async-trait",
+ "axum",
+ "chrono",
+ "http-body",
+ "jsonwebtoken",
+ "once_cell",
+ "serde",
+ "serde_json",
+ "sha256",
+ "sqlx",
+ "tokio",
+ "tower-http",
+ "tracing",
+ "tracing-subscriber",
+ "validator",
+]
+
+[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/migrations/20220822142548_add-users-table.sql b/migrations/20220822142548_add-users-table.sql
deleted file mode 100644
index 4798d7e..0000000
--- a/migrations/20220822142548_add-users-table.sql
+++ /dev/null
@@ -1,6 +0,0 @@
-create table users (
- id serial unique,
- email varchar(100) unique not null,
- password varchar(100) not null,
- is_staff boolean default false
-);
diff --git a/migrations/20220903093057_add-users-table.sql b/migrations/20220903093057_add-users-table.sql
new file mode 100644
index 0000000..0fb83c4
--- /dev/null
+++ b/migrations/20220903093057_add-users-table.sql
@@ -0,0 +1,7 @@
+CREATE TABLE USERS (
+ id SERIAL UNIQUE PRIMARY KEY,
+ email VARCHAR(100) UNIQUE NOT NULL,
+ username VARCHAR(100) UNIQUE NOT NULL,
+ password VARCHAR(100) NOT NULL,
+ is_staff BOOLEAN DEFAULT FALSE
+);
diff --git a/src/main.rs b/src/main.rs
index 508d6cd..4a211fd 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -18,7 +18,7 @@ use tracing::Span;
async fn main() {
let app = create_app().await;
- /// By default the server is bind at "127.0.0.1:3000"
+ // By default the server is bind at "127.0.0.1:3000"
let addr = std::env::var("ALLOWED_HOST").unwrap_or_else(|_| "127.0.0.1:3000".to_string());
tracing::info!("Listening on {}", addr);
diff --git a/src/models/auth.rs b/src/models/auth.rs
index 8b8f61c..7f9ae00 100644
--- a/src/models/auth.rs
+++ b/src/models/auth.rs
@@ -32,6 +32,13 @@ pub struct AuthBody {
token_type: String,
}
+/// Payload used for user creation
+#[derive(Deserialize)]
+pub struct LoginCredentials {
+ pub username: String,
+ pub password: String,
+}
+
static KEYS: Lazy<Keys> = Lazy::new(|| {
let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
Keys::new(secret.as_bytes())
diff --git a/src/models/user.rs b/src/models/user.rs
index 06cde0a..71b35b6 100644
--- a/src/models/user.rs
+++ b/src/models/user.rs
@@ -8,8 +8,10 @@ use validator::Validate;
#[derive(Deserialize, Serialize, Validate)]
pub struct User {
id: i32,
- #[validate(length(min = 1, message = "Can not be empty"))]
+ #[validate(length(min = 4, message = "Can not be empty"))]
email: String,
+ #[validate(length(min = 2, message = "Can not be empty"))]
+ username: String,
#[validate(length(min = 8, message = "Must be min 8 chars length"))]
password: String,
is_staff: Option<bool>,
@@ -21,6 +23,7 @@ pub struct UserList {
// It is public because it used by `Claims` creation
pub id: i32,
email: String,
+ username: String,
is_staff: Option<bool>,
}
@@ -28,15 +31,17 @@ pub struct UserList {
#[derive(Deserialize)]
pub struct UserCreate {
pub email: String,
+ pub username: String,
pub password: String,
}
impl User {
/// By default an user has id = 0. It is not created yet
- pub fn new(email: String, password: String) -> Self {
+ pub fn new(email: String, username: String, password: String) -> Self {
Self {
id: 0,
email,
+ username,
password,
is_staff: Some(false),
}
@@ -54,11 +59,12 @@ impl User {
let rec = sqlx::query_as!(
UserList,
r#"
- INSERT INTO users (email, password)
- VALUES ( $1, $2 )
- RETURNING id, email, is_staff
+ INSERT INTO users (email, username, password)
+ VALUES ( $1, $2, $3)
+ RETURNING id, email, username, is_staff
"#,
user.email,
+ user.username,
crypted_password
)
.fetch_one(pool)
@@ -76,10 +82,10 @@ impl User {
let rec = sqlx::query_as!(
UserList,
r#"
- SELECT id, email, is_staff FROM "users"
- WHERE email = $1 AND password = $2
+ SELECT id, email, username, is_staff FROM "users"
+ WHERE username = $1 AND password = $2
"#,
- user.email,
+ user.username,
crypted_password
)
.fetch_one(pool)
@@ -95,7 +101,7 @@ impl User {
let rec = sqlx::query_as!(
UserList,
r#"
- SELECT id, email, is_staff FROM "users"
+ SELECT id, email, username, is_staff FROM "users"
WHERE id = $1
"#,
user_id
@@ -109,9 +115,12 @@ impl User {
/// List all users
pub async fn list() -> Result<Vec<UserList>, AppError> {
let pool = unsafe { get_client() };
- let rows = sqlx::query_as!(UserList, r#"SELECT id, email, is_staff FROM users"#)
- .fetch_all(pool)
- .await?;
+ let rows = sqlx::query_as!(
+ UserList,
+ r#"SELECT id, email, username, is_staff FROM users"#
+ )
+ .fetch_all(pool)
+ .await?;
Ok(rows)
}
diff --git a/src/routes/auth.rs b/src/routes/auth.rs
index 37c41b2..b667b97 100644
--- a/src/routes/auth.rs
+++ b/src/routes/auth.rs
@@ -1,7 +1,7 @@
use crate::errors::AppError;
use crate::models::{
- auth::{AuthBody, Claims},
- user::{User, UserCreate},
+ auth::{AuthBody, Claims, LoginCredentials},
+ user::User,
};
use axum::{routing::post, Json, Router};
@@ -12,14 +12,14 @@ pub fn create_route() -> Router {
/// Make login. Check if a user with the email and password passed in request body exists into the
/// database
-async fn make_login(Json(payload): Json<UserCreate>) -> Result<Json<AuthBody>, AppError> {
- let user = User::new(payload.email, payload.password);
+async fn make_login(Json(payload): Json<LoginCredentials>) -> Result<Json<AuthBody>, AppError> {
+ let user = User::new(String::new(), payload.username, payload.password);
match User::find(user).await {
Ok(user) => {
let claims = Claims::new(user.id);
let token = claims.get_token()?;
Ok(Json(AuthBody::new(token)))
}
- Err(_) => Err(AppError::NotFound),
+ Err(_) => Err(AppError::NotFound("User not found".to_string())),
}
}
diff --git a/src/routes/user.rs b/src/routes/user.rs
index d44df66..3dfb73a 100644
--- a/src/routes/user.rs
+++ b/src/routes/user.rs
@@ -24,7 +24,7 @@ async fn create_user(
Json(payload): Json<UserCreate>,
_: Claims,
) -> Result<Json<UserList>, AppError> {
- let user = User::new(payload.email, payload.password);
+ let user = User::new(payload.email, payload.username, payload.password);
let user_new = User::create(user).await?;
Ok(Json(user_new))
@@ -34,6 +34,6 @@ async fn create_user(
async fn get_user(Path(user_id): Path<i32>, _: Claims) -> Result<Json<UserList>, AppError> {
match User::find_by_id(user_id).await {
Ok(user) => Ok(Json(user)),
- Err(_) => Err(AppError::NotFound),
+ Err(_) => Err(AppError::NotFound("User not found".to_string())),
}
}