mirror of
https://github.com/ellmau/adf-obdd.git
synced 2025-12-20 09:39:38 +01:00
Add API for getting and updating user
This commit is contained in:
parent
e562631f1c
commit
565683721d
@ -19,7 +19,9 @@ mod user;
|
|||||||
|
|
||||||
use adf::{add_adf_problem, solve_adf_problem};
|
use adf::{add_adf_problem, solve_adf_problem};
|
||||||
use config::{AppState, ASSET_DIRECTORY, COOKIE_DURATION};
|
use config::{AppState, ASSET_DIRECTORY, COOKIE_DURATION};
|
||||||
use user::{create_username_index, delete_account, login, logout, register};
|
use user::{
|
||||||
|
create_username_index, delete_account, login, logout, register, update_user, user_info,
|
||||||
|
};
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
@ -73,7 +75,9 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.service(register)
|
.service(register)
|
||||||
.service(delete_account)
|
.service(delete_account)
|
||||||
.service(login)
|
.service(login)
|
||||||
.service(logout),
|
.service(logout)
|
||||||
|
.service(user_info)
|
||||||
|
.service(update_user),
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::scope("/adf")
|
web::scope("/adf")
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
use actix_identity::Identity;
|
use actix_identity::Identity;
|
||||||
use actix_web::{delete, post, web, HttpMessage, HttpRequest, HttpResponse, Responder};
|
use actix_web::{delete, get, post, put, web, HttpMessage, HttpRequest, HttpResponse, Responder};
|
||||||
use argon2::password_hash::rand_core::OsRng;
|
use argon2::password_hash::rand_core::OsRng;
|
||||||
use argon2::password_hash::SaltString;
|
use argon2::password_hash::SaltString;
|
||||||
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier};
|
||||||
use mongodb::results::DeleteResult;
|
use mongodb::results::{DeleteResult, UpdateResult};
|
||||||
use mongodb::{bson::doc, options::IndexOptions, Client, IndexModel};
|
use mongodb::{bson::doc, options::IndexOptions, Client, IndexModel};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -22,6 +22,12 @@ struct UserPayload {
|
|||||||
password: String,
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct UserInfo {
|
||||||
|
username: String,
|
||||||
|
temp: bool,
|
||||||
|
}
|
||||||
|
|
||||||
// Creates an index on the "username" field to force the values to be unique.
|
// Creates an index on the "username" field to force the values to be unique.
|
||||||
pub(crate) async fn create_username_index(client: &Client) {
|
pub(crate) async fn create_username_index(client: &Client) {
|
||||||
let options = IndexOptions::builder().unique(true).build();
|
let options = IndexOptions::builder().unique(true).build();
|
||||||
@ -215,3 +221,128 @@ async fn logout(app_state: web::Data<AppState>, id: Option<Identity>) -> impl Re
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current user
|
||||||
|
#[get("/info")]
|
||||||
|
async fn user_info(app_state: web::Data<AppState>, identity: Option<Identity>) -> impl Responder {
|
||||||
|
let user_coll: mongodb::Collection<User> = app_state
|
||||||
|
.mongodb_client
|
||||||
|
.database(DB_NAME)
|
||||||
|
.collection(USER_COLL);
|
||||||
|
|
||||||
|
match identity.map(|id| id.id()) {
|
||||||
|
None => {
|
||||||
|
HttpResponse::Unauthorized().body("You need to login get your account information.")
|
||||||
|
}
|
||||||
|
Some(Err(err)) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
Some(Ok(username)) => {
|
||||||
|
match user_coll
|
||||||
|
.find_one(doc! { "username": &username }, None)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Some(user)) => {
|
||||||
|
let info = UserInfo {
|
||||||
|
username: user.username,
|
||||||
|
temp: user.password.is_none(),
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpResponse::Ok().json(info)
|
||||||
|
}
|
||||||
|
Ok(None) => HttpResponse::NotFound().body("Logged in user does not exist anymore."),
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update current user
|
||||||
|
#[put("/update")]
|
||||||
|
async fn update_user(
|
||||||
|
req: HttpRequest,
|
||||||
|
app_state: web::Data<AppState>,
|
||||||
|
identity: Option<Identity>,
|
||||||
|
user: web::Json<UserPayload>,
|
||||||
|
) -> impl Responder {
|
||||||
|
let mut user: UserPayload = user.into_inner();
|
||||||
|
let user_coll = app_state
|
||||||
|
.mongodb_client
|
||||||
|
.database(DB_NAME)
|
||||||
|
.collection(USER_COLL);
|
||||||
|
let adf_coll: mongodb::Collection<AdfProblem> = app_state
|
||||||
|
.mongodb_client
|
||||||
|
.database(DB_NAME)
|
||||||
|
.collection(ADF_COLL);
|
||||||
|
|
||||||
|
match identity {
|
||||||
|
None => {
|
||||||
|
HttpResponse::Unauthorized().body("You need to login get your account information.")
|
||||||
|
}
|
||||||
|
Some(id) => match id.id() {
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
Ok(username) => {
|
||||||
|
if &user.username != &username && username_exists(&user_coll, &user.username).await
|
||||||
|
{
|
||||||
|
return HttpResponse::Conflict()
|
||||||
|
.body("Username is already taken. Please pick another one!");
|
||||||
|
}
|
||||||
|
|
||||||
|
let pw = &user.password;
|
||||||
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
|
let hashed_pw = Argon2::default()
|
||||||
|
.hash_password(pw.as_bytes(), &salt)
|
||||||
|
.expect("Error while hashing password!")
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
user.password = hashed_pw;
|
||||||
|
|
||||||
|
let result = user_coll
|
||||||
|
.replace_one(
|
||||||
|
doc! { "username": &username },
|
||||||
|
User {
|
||||||
|
username: user.username.clone(),
|
||||||
|
password: Some(user.password),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
match result {
|
||||||
|
Ok(UpdateResult {
|
||||||
|
modified_count: 0, ..
|
||||||
|
}) => HttpResponse::InternalServerError().body("Account could not be updated."),
|
||||||
|
Ok(UpdateResult {
|
||||||
|
modified_count: 1, ..
|
||||||
|
}) => {
|
||||||
|
// re-login with new username
|
||||||
|
Identity::login(&req.extensions(), user.username.clone()).unwrap();
|
||||||
|
|
||||||
|
// update all adf problems of user
|
||||||
|
match adf_coll
|
||||||
|
.update_many(
|
||||||
|
doc! { "username": &username },
|
||||||
|
doc! { "$set": { "username": &user.username } },
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
Ok(UpdateResult {
|
||||||
|
modified_count: 0, ..
|
||||||
|
}) => HttpResponse::InternalServerError()
|
||||||
|
.body("Account could not be updated."),
|
||||||
|
Ok(UpdateResult {
|
||||||
|
modified_count: _, ..
|
||||||
|
}) => HttpResponse::Ok().json(UserInfo {
|
||||||
|
username: user.username,
|
||||||
|
temp: false,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(_) => unreachable!(
|
||||||
|
"replace_one replaces at most one entry so all cases are covered already"
|
||||||
|
),
|
||||||
|
Err(err) => HttpResponse::InternalServerError().body(err.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user