From 5c23f326b69dadf1319add8e7582c2bd3a42f644 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Sun, 1 Dec 2024 11:14:28 -0500 Subject: [PATCH] Add the ability to save users and games. Link games more tightly to characters --- visions/server/src/database.rs | 86 +++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/visions/server/src/database.rs b/visions/server/src/database.rs index 406264c..57b7dec 100644 --- a/visions/server/src/database.rs +++ b/visions/server/src/database.rs @@ -240,6 +240,69 @@ impl DiskDb { } } + fn save_user( + &self, + user_id: Option, + name: &str, + password: &str, + admin: bool, + enabled: bool, + ) -> Result { + match user_id { + None => { + let user_id = UserId::new(); + let mut stmt = self + .conn + .prepare("INSERT INTO users VALUES (?, ?, ?, ?, ?)") + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + stmt.execute((user_id.as_str(), name, password, admin, enabled)) + .unwrap(); + Ok(user_id) + } + Some(user_id) => { + let mut stmt = self + .conn + .prepare( + "UPDATE users SET name=?, password=?, admin=?, enbabled=? WHERE uuid=?", + ) + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + stmt.execute((name, password, admin, enabled, user_id.as_str())) + .unwrap(); + Ok(user_id) + } + } + } + + fn save_game( + &self, + game_id: Option, + name: &str, + ) -> Result { + match game_id { + None => { + let game_id = GameId::new(); + let mut stmt = self + .conn + .prepare("INSERT INTO games VALUES (?, ?)") + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + stmt.execute((game_id.as_str(), name)) + .unwrap(); + Ok(game_id) + } + Some(game_id) => { + let mut stmt = self + .conn + .prepare( + "UPDATE games SET name=? WHERE uuid=?", + ) + .map_err(|err| FatalError::ConstructQueryFailure(format!("{}", err)))?; + stmt.execute((name, game_id.as_str())) + .unwrap(); + Ok(game_id) + } + } + } + fn character(&self, id: CharacterId) -> Result, FatalError> { let mut stmt = self .conn @@ -267,7 +330,7 @@ impl DiskDb { fn save_character( &self, char_id: Option, - game_type: String, + game: GameId, character: serde_json::Value, ) -> std::result::Result { match char_id { @@ -277,7 +340,7 @@ impl DiskDb { .conn .prepare("INSERT INTO characters VALUES (?, ?, ?)") .unwrap(); - stmt.execute((char_id.as_str(), game_type, character.to_string())) + stmt.execute((char_id.as_str(), game.as_str(), character.to_string())) .unwrap(); Ok(char_id) @@ -373,16 +436,24 @@ mod test { const soren: &'static str = r#"{ "type_": "Candela", "name": "Soren Jensen", "pronouns": "he/him", "circle": "Circle of the Bluest Sky", "style": "dapper gentleman", "catalyst": "a cursed book", "question": "What were the contents of that book?", "nerve": { "type_": "nerve", "drives": { "current": 1, "max": 2 }, "resistances": { "current": 0, "max": 3 }, "move": { "gilded": false, "score": 2 }, "strike": { "gilded": false, "score": 1 }, "control": { "gilded": true, "score": 0 } }, "cunning": { "type_": "cunning", "drives": { "current": 1, "max": 1 }, "resistances": { "current": 0, "max": 3 }, "sway": { "gilded": false, "score": 0 }, "read": { "gilded": false, "score": 0 }, "hide": { "gilded": false, "score": 0 } }, "intuition": { "type_": "intuition", "drives": { "current": 0, "max": 0 }, "resistances": { "current": 0, "max": 3 }, "survey": { "gilded": false, "score": 0 }, "focus": { "gilded": false, "score": 0 }, "sense": { "gilded": false, "score": 0 } }, "role": "Slink", "role_abilities": [ "Scout: If you have time to observe a location, you can spend 1 Intuition to ask a question: What do I notice here that others do not see? What in this place might be of use to us? What path should we follow?" ], "specialty": "Detective", "specialty_abilities": [ "Mind Palace: When you want to figure out how two clues might relate or what path they should point you towards, burn 1 Intution resistance. The GM will give you the information you have deduced." ] }"#; - #[test] - fn it_can_retrieve_a_character() { + fn setup_db() -> (DiskDb, GameId) { let no_path: Option = None; let db = DiskDb::new(no_path).unwrap(); + db.save_user(None, "admin", "abcdefg", true, true); + let game_id = db.save_game(None, "Candela").unwrap(); + (db, game_id) + } + + #[test] + fn it_can_retrieve_a_character() { + let (db, game_id) = setup_db(); + assert_matches!(db.character(CharacterId::from("1")), Ok(None)); let js: serde_json::Value = serde_json::from_str(soren).unwrap(); let soren_id = db - .save_character(None, "candela".to_owned(), js.clone()) + .save_character(None, game_id, js.clone()) .unwrap(); assert_matches!(db.character(soren_id).unwrap(), Some(CharsheetRow{ data, .. }) => assert_eq!(js, data)); } @@ -392,6 +463,9 @@ mod test { let memory_db: Option = None; let mut conn = DbConn::new(memory_db); - assert_matches!(conn.character(CharacterId::from("1")).await, ResultExt::Ok(None)); + assert_matches!( + conn.character(CharacterId::from("1")).await, + ResultExt::Ok(None) + ); } }