use sqlx::query! macro
This commit is contained in:
parent
c89ee29d4d
commit
3cb122306a
12
.sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json
generated
Normal file
12
.sqlx/query-73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a.json
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "DELETE FROM users WHERE id = ?",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 1
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "73ffdf5be39aa5c4c160c2f77d6634a6970eeb4e1d3395f045ded747f0ce9d2a"
|
||||||
|
}
|
20
.sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json
generated
Normal file
20
.sqlx/query-b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4.json
generated
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n SELECT COUNT(*) as \"count!: i32\"\n FROM users\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "count!: i32",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 0
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "b668f6787e6425e15414bb745bce55788deb3a996b8e51d651a9e4a07b1483b4"
|
||||||
|
}
|
12
.sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json
generated
Normal file
12
.sqlx/query-bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8.json
generated
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"db_name": "SQLite",
|
||||||
|
"query": "\n INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin) \n VALUES (?, ?, ?, ?, ?, ?, ?)\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Right": 7
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "bf1cc32644e82c80cd6ab4d8fec843384da66c0cac7d6f8f929470c72284d8c8"
|
||||||
|
}
|
106
src/user.rs
106
src/user.rs
@ -45,19 +45,22 @@ impl User {
|
|||||||
where
|
where
|
||||||
E: sqlx::Executor<'a, Database = sqlx::Sqlite>,
|
E: sqlx::Executor<'a, Database = sqlx::Sqlite>,
|
||||||
{
|
{
|
||||||
sqlx::query(
|
let id_str = self.id.to_string();
|
||||||
|
let created_at_str = self.created_at.to_rfc3339();
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin)
|
INSERT INTO users (id, username, password_hash, email, display_name, created_at, admin)
|
||||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||||
"#,
|
"#,
|
||||||
|
id_str,
|
||||||
|
self.username,
|
||||||
|
self.password_hash,
|
||||||
|
self.email,
|
||||||
|
self.display_name,
|
||||||
|
created_at_str,
|
||||||
|
self.admin
|
||||||
)
|
)
|
||||||
.bind(self.id.to_string())
|
|
||||||
.bind(self.username.clone())
|
|
||||||
.bind(self.password_hash.clone())
|
|
||||||
.bind(self.email.clone())
|
|
||||||
.bind(self.display_name.clone())
|
|
||||||
.bind(self.created_at.to_rfc3339())
|
|
||||||
.bind(self.admin)
|
|
||||||
.execute(executor)
|
.execute(executor)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@ -173,12 +176,15 @@ pub async fn delete_user(mut db: Connection<Db>, user_id: &str) -> Status {
|
|||||||
Err(_) => return Status::BadRequest,
|
Err(_) => return Status::BadRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
let query = sqlx::query("DELETE FROM users WHERE id = ?")
|
let id_str = uuid.to_string();
|
||||||
.bind(uuid.to_string())
|
let result = sqlx::query!(
|
||||||
|
"DELETE FROM users WHERE id = ?",
|
||||||
|
id_str
|
||||||
|
)
|
||||||
.execute(&mut **db)
|
.execute(&mut **db)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match query {
|
match result {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
if result.rows_affected() > 0 {
|
if result.rows_affected() > 0 {
|
||||||
Status::NoContent
|
Status::NoContent
|
||||||
@ -201,6 +207,7 @@ pub async fn login(
|
|||||||
sessions: &State<SessionStore>,
|
sessions: &State<SessionStore>,
|
||||||
) -> Result<Json<LoginResponse>, Status> {
|
) -> Result<Json<LoginResponse>, Status> {
|
||||||
let creds = credentials.into_inner();
|
let creds = credentials.into_inner();
|
||||||
|
let username = creds.username.clone();
|
||||||
|
|
||||||
// Find user by username
|
// Find user by username
|
||||||
let user = sqlx::query!(
|
let user = sqlx::query!(
|
||||||
@ -212,7 +219,7 @@ pub async fn login(
|
|||||||
FROM users
|
FROM users
|
||||||
WHERE username = ?
|
WHERE username = ?
|
||||||
"#,
|
"#,
|
||||||
creds.username
|
username
|
||||||
)
|
)
|
||||||
.fetch_optional(&mut **db)
|
.fetch_optional(&mut **db)
|
||||||
.await
|
.await
|
||||||
@ -300,19 +307,21 @@ impl<'r> rocket::request::FromRequest<'r> for AuthenticatedUser {
|
|||||||
#[get("/setup")]
|
#[get("/setup")]
|
||||||
pub async fn setup_page(mut db: Connection<Db>) -> Result<Template, Status> {
|
pub async fn setup_page(mut db: Connection<Db>) -> Result<Template, Status> {
|
||||||
// Check if any users exist
|
// Check if any users exist
|
||||||
let count = sqlx::query!("SELECT COUNT(*) as count FROM users")
|
let count = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT COUNT(*) as "count!: i32"
|
||||||
|
FROM users
|
||||||
|
"#
|
||||||
|
)
|
||||||
.fetch_one(&mut **db)
|
.fetch_one(&mut **db)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Status::InternalServerError)?
|
.map_err(|_| Status::InternalServerError)?;
|
||||||
.count;
|
|
||||||
|
|
||||||
if count > 0 {
|
if count.count > 0 {
|
||||||
// If users exist, redirect to login
|
return Err(Status::Forbidden);
|
||||||
Err(Status::SeeOther)
|
|
||||||
} else {
|
|
||||||
// Show setup page
|
|
||||||
Ok(Template::render("setup", context! {}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(Template::render("setup", context! {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/setup", data = "<new_user>")]
|
#[post("/setup", data = "<new_user>")]
|
||||||
@ -320,33 +329,33 @@ pub async fn setup(
|
|||||||
mut db: Connection<Db>,
|
mut db: Connection<Db>,
|
||||||
new_user: Json<NewUser>,
|
new_user: Json<NewUser>,
|
||||||
) -> Result<Status, Json<SetupError>> {
|
) -> Result<Status, Json<SetupError>> {
|
||||||
let new_user = new_user.into_inner();
|
|
||||||
|
|
||||||
// Check if any users exist
|
// Check if any users exist
|
||||||
let count = sqlx::query!("SELECT COUNT(*) as count FROM users")
|
let count = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
SELECT COUNT(*) as "count!: i32"
|
||||||
|
FROM users
|
||||||
|
"#
|
||||||
|
)
|
||||||
.fetch_one(&mut **db)
|
.fetch_one(&mut **db)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|_| {
|
||||||
eprintln!("Database error: {}", e);
|
|
||||||
Json(SetupError {
|
Json(SetupError {
|
||||||
error: "Internal server error".to_string(),
|
error: "Database error".to_string(),
|
||||||
})
|
})
|
||||||
})?
|
})?;
|
||||||
.count;
|
|
||||||
|
|
||||||
if count > 0 {
|
if count.count > 0 {
|
||||||
return Err(Json(SetupError {
|
return Err(Json(SetupError {
|
||||||
error: "Setup has already been completed".to_string(),
|
error: "Setup already completed".to_string(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let password = new_user.password.as_bytes();
|
let new_user = new_user.into_inner();
|
||||||
|
|
||||||
// Hash the password
|
// Hash the password - we'll use bcrypt
|
||||||
let password_hash = bcrypt::hash(password, bcrypt::DEFAULT_COST).map_err(|e| {
|
let password_hash = bcrypt::hash(new_user.password.as_bytes(), bcrypt::DEFAULT_COST).map_err(|_| {
|
||||||
eprintln!("Password hashing error: {}", e);
|
|
||||||
Json(SetupError {
|
Json(SetupError {
|
||||||
error: "Failed to process password".to_string(),
|
error: "Failed to hash password".to_string(),
|
||||||
})
|
})
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@ -356,22 +365,13 @@ pub async fn setup(
|
|||||||
new_user.email,
|
new_user.email,
|
||||||
new_user.display_name,
|
new_user.display_name,
|
||||||
);
|
);
|
||||||
user.admin = true; // This is an admin user
|
user.admin = true;
|
||||||
|
|
||||||
match user.write_to_database(&mut **db).await {
|
user.write_to_database(&mut **db)
|
||||||
Ok(_) => Ok(Status::Created),
|
.await
|
||||||
Err(e) => {
|
.map_err(|_| Json(SetupError {
|
||||||
error!("Database error: {}", e);
|
|
||||||
match e {
|
|
||||||
sqlx::Error::Database(db_err) if db_err.is_unique_violation() => {
|
|
||||||
Err(Json(SetupError {
|
|
||||||
error: "Username already exists".to_string(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
_ => Err(Json(SetupError {
|
|
||||||
error: "Failed to create user".to_string(),
|
error: "Failed to create user".to_string(),
|
||||||
})),
|
}))?;
|
||||||
}
|
|
||||||
}
|
Ok(Status::Created)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user