feat: Implement user management with a new add_user binary and refactor state handling into a dedicated store module.
This commit is contained in:
parent
6bdfb49d59
commit
f49900adad
@ -2,6 +2,8 @@
|
|||||||
name = "backend"
|
name = "backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
default-run = "backend"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
prost = "0.14.1"
|
prost = "0.14.1"
|
||||||
|
|||||||
55
backend/src/bin/add_user.rs
Normal file
55
backend/src/bin/add_user.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use backend::items::Person;
|
||||||
|
use backend::store::{self, User, save_state};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("Add User Tool");
|
||||||
|
println!("-------------");
|
||||||
|
|
||||||
|
print!("Username: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut username = String::new();
|
||||||
|
io::stdin().read_line(&mut username).unwrap();
|
||||||
|
let username = username.trim().to_string();
|
||||||
|
|
||||||
|
if username.is_empty() {
|
||||||
|
println!("Username cannot be empty.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("Password: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
let mut password = String::new();
|
||||||
|
io::stdin().read_line(&mut password).unwrap();
|
||||||
|
let password = password.trim().to_string();
|
||||||
|
|
||||||
|
if password.is_empty() {
|
||||||
|
println!("Password cannot be empty.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (games, mut users) = store::load_state().unwrap_or_else(|| {
|
||||||
|
println!("No existing state found. Creating new state.");
|
||||||
|
(Vec::new(), Vec::new())
|
||||||
|
});
|
||||||
|
|
||||||
|
if users.iter().any(|u| u.person.name == username) {
|
||||||
|
println!("User '{}' already exists.", username);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let password_hash = bcrypt::hash(&password, bcrypt::DEFAULT_COST).unwrap();
|
||||||
|
|
||||||
|
let new_user = User {
|
||||||
|
person: Person {
|
||||||
|
name: username.clone(),
|
||||||
|
opinion: Vec::new(),
|
||||||
|
},
|
||||||
|
password_hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
users.push(new_user);
|
||||||
|
save_state(&games, &users);
|
||||||
|
|
||||||
|
println!("User '{}' added successfully.", username);
|
||||||
|
}
|
||||||
12
backend/src/lib.rs
Normal file
12
backend/src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate rocket;
|
||||||
|
|
||||||
|
pub mod items {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/items.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
|
pub mod proto_utils;
|
||||||
|
pub mod store;
|
||||||
|
|
||||||
|
pub use store::User;
|
||||||
@ -1,63 +1,14 @@
|
|||||||
use rocket::fs::FileServer;
|
use rocket::fs::FileServer;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::BufReader;
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use crate::items::Game;
|
use backend::auth;
|
||||||
|
use backend::items::{self, Game};
|
||||||
|
use backend::proto_utils;
|
||||||
|
use backend::store::{self, User, save_state};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
|
|
||||||
pub mod items {
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/items.rs"));
|
|
||||||
}
|
|
||||||
|
|
||||||
mod auth;
|
|
||||||
mod proto_utils;
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct User {
|
|
||||||
pub person: items::Person,
|
|
||||||
pub password_hash: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for User {
|
|
||||||
type Target = items::Person;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.person
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
struct PersistentState {
|
|
||||||
games: Vec<Game>,
|
|
||||||
users: Vec<User>,
|
|
||||||
}
|
|
||||||
|
|
||||||
const STATE_FILE: &str = "state.json";
|
|
||||||
|
|
||||||
fn save_state(games: &[Game], users: &[User]) {
|
|
||||||
let state = PersistentState {
|
|
||||||
games: games.to_vec(),
|
|
||||||
users: users.to_vec(),
|
|
||||||
};
|
|
||||||
if let Ok(file) = File::create(STATE_FILE) {
|
|
||||||
let _ = serde_json::to_writer_pretty(file, &state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_state() -> Option<(Vec<Game>, Vec<User>)> {
|
|
||||||
if let Ok(file) = File::open(STATE_FILE) {
|
|
||||||
let reader = BufReader::new(file);
|
|
||||||
if let Ok(state) = serde_json::from_reader::<_, PersistentState>(reader) {
|
|
||||||
return Some((state.games, state.users));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/<name>")]
|
#[get("/<name>")]
|
||||||
fn get_user(
|
fn get_user(
|
||||||
_token: auth::Token,
|
_token: auth::Token,
|
||||||
@ -178,7 +129,7 @@ async fn index_fallback() -> Option<rocket::fs::NamedFile> {
|
|||||||
|
|
||||||
#[rocket::main]
|
#[rocket::main]
|
||||||
async fn main() -> Result<(), std::io::Error> {
|
async fn main() -> Result<(), std::io::Error> {
|
||||||
let (game_list, user_list) = load_state().unwrap_or_else(|| {
|
let (game_list, user_list) = store::load_state().unwrap_or_else(|| {
|
||||||
let mut game_list: Vec<Game> = Vec::new();
|
let mut game_list: Vec<Game> = Vec::new();
|
||||||
let mut user_list: Vec<User> = Vec::new();
|
let mut user_list: Vec<User> = Vec::new();
|
||||||
|
|
||||||
|
|||||||
46
backend/src/store.rs
Normal file
46
backend/src/store.rs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
use crate::items::{Game, Person};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::BufReader;
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct User {
|
||||||
|
pub person: Person,
|
||||||
|
pub password_hash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for User {
|
||||||
|
type Target = Person;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.person
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct PersistentState {
|
||||||
|
pub games: Vec<Game>,
|
||||||
|
pub users: Vec<User>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const STATE_FILE: &str = "state.json";
|
||||||
|
|
||||||
|
pub fn save_state(games: &[Game], users: &[User]) {
|
||||||
|
let state = PersistentState {
|
||||||
|
games: games.to_vec(),
|
||||||
|
users: users.to_vec(),
|
||||||
|
};
|
||||||
|
if let Ok(file) = File::create(STATE_FILE) {
|
||||||
|
let _ = serde_json::to_writer_pretty(file, &state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_state() -> Option<(Vec<Game>, Vec<User>)> {
|
||||||
|
if let Ok(file) = File::open(STATE_FILE) {
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
if let Ok(state) = serde_json::from_reader::<_, PersistentState>(reader) {
|
||||||
|
return Some((state.games, state.users));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user