diff --git a/Cargo.lock b/Cargo.lock index 0626f9a..e2e23e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,6 +426,7 @@ dependencies = [ "geoffrey_models", "log", "rand 0.8.4", + "regex", "serde 1.0.130", "serde_json", "simple_logger", diff --git a/geoffrey_api/Cargo.toml b/geoffrey_api/Cargo.toml index 18a81b2..863299e 100644 --- a/geoffrey_api/Cargo.toml +++ b/geoffrey_api/Cargo.toml @@ -17,4 +17,5 @@ config = "0.11.0" structopt = "0.3.21" log = "0.4.14" simple_logger = "1.13.0" -rand = "0.8.4" \ No newline at end of file +rand = "0.8.4" +regex = "1.5.4" \ No newline at end of file diff --git a/geoffrey_api/src/commands/mod.rs b/geoffrey_api/src/commands/mod.rs index ae803dd..3d758a5 100644 --- a/geoffrey_api/src/commands/mod.rs +++ b/geoffrey_api/src/commands/mod.rs @@ -3,6 +3,7 @@ use crate::commands::add_location::AddLocation; use crate::commands::find::FindCommand; use crate::commands::register::Register; use crate::commands::selling::Selling; +use crate::commands::set_portal::SetPortal; use crate::context::Context; use crate::helper::{get_player_from_req, get_token_from_req}; use crate::Result; @@ -25,6 +26,7 @@ pub mod add_token; pub mod find; pub mod register; pub mod selling; +pub mod set_portal; #[derive(Debug, Clone, PartialEq)] #[allow(clippy::upper_case_acronyms)] @@ -122,6 +124,7 @@ pub fn command_filter( .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx.clone())) .or(create_command_filter::(ctx.clone())) - .or(create_command_filter::(ctx)), + .or(create_command_filter::(ctx.clone())) + .or(create_command_filter::(ctx)), ) } diff --git a/geoffrey_api/src/commands/selling.rs b/geoffrey_api/src/commands/selling.rs index 20e974e..bb65456 100644 --- a/geoffrey_api/src/commands/selling.rs +++ b/geoffrey_api/src/commands/selling.rs @@ -53,7 +53,7 @@ impl Command for Selling { listing: item.clone(), shop_name: shop.name.clone(), shop_loc: shop.position, - portal: shop.tunnel.clone(), + portal: shop.portal.clone(), }) } else { None diff --git a/geoffrey_api/src/commands/set_portal.rs b/geoffrey_api/src/commands/set_portal.rs new file mode 100644 index 0000000..c94f463 --- /dev/null +++ b/geoffrey_api/src/commands/set_portal.rs @@ -0,0 +1,48 @@ +use crate::commands::{Command, RequestType}; +use crate::context::Context; +use crate::Result; +use geoffrey_db::helper::load_location; +use geoffrey_models::models::locations::{Location, LocationDb}; +use geoffrey_models::models::parameters::set_portal_params::SetPortalParams; +use geoffrey_models::models::player::Player; +use geoffrey_models::models::response::api_error::GeoffreyAPIError; +use geoffrey_models::models::CommandLevel; +use std::sync::Arc; + +pub struct SetPortal {} + +impl Command for SetPortal { + type Req = SetPortalParams; + type Resp = Location; + + fn command_name() -> String { + "set_portal".to_string() + } + + fn request_type() -> RequestType { + RequestType::POST + } + + fn command_level() -> CommandLevel { + CommandLevel::REGISTERED + } + + fn run_command(ctx: Arc, req: Self::Req, user: Option) -> Result { + let user = user.unwrap(); + let filter = regex::Regex::new(format!(r"(?i)^{}$", req.loc_name).as_str()).unwrap(); + + let mut location: LocationDb = ctx + .db + .filter(|_, loc: &LocationDb| { + loc.owners().contains(&user.id.unwrap()) && filter.is_match(loc.name.as_str()) + })? + .next() + .ok_or(GeoffreyAPIError::EntryNotFound)?; + + location.portal = Some(req.portal); + + let location = ctx.db.insert(location)?; + + load_location(&ctx.db, &location).map_err(|err| err.into()) + } +} diff --git a/geoffrey_db/src/database.rs b/geoffrey_db/src/database.rs index 79ab5f4..b608e46 100644 --- a/geoffrey_db/src/database.rs +++ b/geoffrey_db/src/database.rs @@ -1,15 +1,15 @@ use crate::error::{GeoffreyDBError, Result}; +use crate::migration::do_migration; +use geoffrey_models::models::db_metadata::DBMetadata; use geoffrey_models::GeoffreyDatabaseModel; use std::convert::TryInto; use std::path::Path; -use geoffrey_models::models::db_metadata::DBMetadata; -use crate::migration::do_migration; -const DB_VERSION: u64 = 2; +const DB_VERSION: u64 = 3; const DB_METADATA_ID: u64 = 1; pub struct Database { - pub(crate) db: sled::Db, + pub(crate) db: sled::Db, } impl Database { diff --git a/geoffrey_db/src/migration/migration_2.rs b/geoffrey_db/src/migration/migration_2.rs index c223bf5..50a1108 100644 --- a/geoffrey_db/src/migration/migration_2.rs +++ b/geoffrey_db/src/migration/migration_2.rs @@ -1,10 +1,10 @@ -use crate::migration::Migration; use crate::database::Database; +use crate::migration::Migration; use geoffrey_models::models::locations::LocationDb; use geoffrey_models::GeoffreyDatabaseModel; use json::JsonValue; -pub(crate) struct PosAndNetherMigration {} +pub(crate) struct PosAndNetherMigration {} impl Migration for PosAndNetherMigration { fn up(db: &Database) -> crate::error::Result<()> { @@ -36,7 +36,7 @@ impl Migration for PosAndNetherMigration { let (id, loc_ivec) = entry?; let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap(); - loc["position"]["y"] = loc["position"]["z"].clone(); + loc["position"]["y"] = loc["position"]["z"].clone(); loc["position"]["z"].clear(); // Clear out the tunnel entry, there is not a great way to convert @@ -46,7 +46,6 @@ impl Migration for PosAndNetherMigration { } Ok(()) - } fn version() -> u64 { @@ -57,12 +56,12 @@ impl Migration for PosAndNetherMigration { #[cfg(test)] mod tests { use crate::database::Database; - use std::path::Path; + use crate::migration::migration_2::PosAndNetherMigration; + use crate::migration::Migration; use geoffrey_models::models::locations::LocationDb; use geoffrey_models::GeoffreyDatabaseModel; use sled::IVec; - use crate::migration::migration_2::PosAndNetherMigration; - use crate::migration::Migration; + use std::path::Path; #[test] fn test_migration_2() { @@ -70,7 +69,8 @@ mod tests { let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap(); - let old_loc_format = json::parse(r#"{ + let old_loc_format = json::parse( + r#"{ "id": 55, "name": "Test", "position": { @@ -79,9 +79,13 @@ mod tests { "dimension": "Overworld" }, "loc_data": "Base" - }"#).unwrap(); + }"#, + ) + .unwrap(); - loc_tree.insert(IVec::from(vec![55]), old_loc_format.to_string().as_bytes()).unwrap(); + loc_tree + .insert(IVec::from(vec![55]), old_loc_format.to_string().as_bytes()) + .unwrap(); PosAndNetherMigration::up(&db).unwrap(); @@ -95,4 +99,4 @@ mod tests { std::fs::remove_dir_all("../migration_2_db").unwrap(); } -} \ No newline at end of file +} diff --git a/geoffrey_db/src/migration/migration_3.rs b/geoffrey_db/src/migration/migration_3.rs new file mode 100644 index 0000000..6fac2e5 --- /dev/null +++ b/geoffrey_db/src/migration/migration_3.rs @@ -0,0 +1,99 @@ +use crate::database::Database; +use crate::migration::Migration; +use geoffrey_models::models::locations::LocationDb; +use geoffrey_models::GeoffreyDatabaseModel; + +pub(crate) struct TunnelToPortalMigration {} + +impl Migration for TunnelToPortalMigration { + fn up(db: &Database) -> crate::error::Result<()> { + let loc_tree = db.db.open_tree(LocationDb::tree())?; + + for entry in loc_tree.iter() { + let (id, loc_ivec) = entry?; + let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap(); + + let tunnel = loc["tunnel"].clone(); + + loc["portal"] = tunnel; + + loc_tree.insert(id, loc.to_string().as_bytes())?; + } + + Ok(()) + } + + fn down(db: &Database) -> crate::error::Result<()> { + let loc_tree = db.db.open_tree(LocationDb::tree())?; + + for entry in loc_tree.iter() { + let (id, loc_ivec) = entry?; + let mut loc = json::parse(std::str::from_utf8(&loc_ivec).unwrap()).unwrap(); + + let portal = loc["portal"].clone(); + + loc["tunnel"] = portal; + + loc_tree.insert(id, loc.to_string().as_bytes())?; + } + + Ok(()) + } + + fn version() -> u64 { + 2 + } +} + +#[cfg(test)] +mod tests { + use crate::database::Database; + use crate::migration::migration_3::TunnelToPortalMigration; + use crate::migration::Migration; + use geoffrey_models::models::locations::LocationDb; + use geoffrey_models::GeoffreyDatabaseModel; + use sled::IVec; + use std::path::Path; + + #[test] + fn test_migration_2() { + let db = Database::new(Path::new("../migration_3_db/")).unwrap(); + + let loc_tree = db.db.open_tree(LocationDb::tree()).unwrap(); + + let old_loc = json::parse( + r#"{ + "id": 55, + "name": "Test", + "position": { + "x": 55, + "y": 55, + "z": 55, + "dimension": "Overworld" + }, + "tunnel": { + "x": 8, + "z": 8 + }, + "loc_data": "Base" + }"#, + ) + .unwrap(); + + loc_tree + .insert(IVec::from(vec![55]), old_loc.to_string().as_bytes()) + .unwrap(); + + TunnelToPortalMigration::up(&db).unwrap(); + + let new_loc = loc_tree.get(IVec::from(vec![55])).unwrap().unwrap(); + let new_loc = json::parse(std::str::from_utf8(&new_loc).unwrap()).unwrap(); + + assert_eq!(new_loc["portal"]["x"], 8); + assert_eq!(new_loc["portal"]["z"], 8); + + drop(db); + + std::fs::remove_dir_all("../migration_3_db").unwrap(); + } +} diff --git a/geoffrey_db/src/migration/mod.rs b/geoffrey_db/src/migration/mod.rs index d2d0b7f..22bc7af 100644 --- a/geoffrey_db/src/migration/mod.rs +++ b/geoffrey_db/src/migration/mod.rs @@ -1,9 +1,11 @@ use crate::database::Database; use crate::error::Result; use crate::migration::migration_2::PosAndNetherMigration; +use crate::migration::migration_3::TunnelToPortalMigration; use geoffrey_models::models::db_metadata::DBMetadata; mod migration_2; +mod migration_3; trait Migration { fn up(db: &Database) -> Result<()>; @@ -12,10 +14,11 @@ trait Migration { } fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> { - for ver in current_version+1..=target_version { + for ver in current_version + 1..=target_version { match ver { 2 => PosAndNetherMigration::up(db)?, - _ => () + 3 => TunnelToPortalMigration::up(db)?, + _ => (), } } @@ -25,8 +28,9 @@ fn upgrade(db: &Database, current_version: u64, target_version: u64) -> Result<( fn downgrade(db: &Database, current_version: u64, target_version: u64) -> Result<()> { for ver in (target_version..current_version).rev() { match ver { - 2 => PosAndNetherMigration::up(db)?, - _ => () + 2 => PosAndNetherMigration::down(db)?, + 3 => TunnelToPortalMigration::down(db)?, + _ => (), } } @@ -36,11 +40,11 @@ fn downgrade(db: &Database, current_version: u64, target_version: u64) -> Result pub fn do_migration(db: &Database, target_version: u64) -> Result<()> { let current_version = db.version().unwrap_or(0); + #[allow(clippy::comparison_chain)] if target_version > current_version { upgrade(db, current_version, target_version)?; - } - else if target_version < current_version { - downgrade(db, current_version, target_version)?; + } else if target_version < current_version { + downgrade(db, current_version, target_version)?; } let metadata = DBMetadata { diff --git a/geoffrey_models/src/lib.rs b/geoffrey_models/src/lib.rs index 73d86db..fd7afcb 100644 --- a/geoffrey_models/src/lib.rs +++ b/geoffrey_models/src/lib.rs @@ -5,7 +5,6 @@ use std::fmt::Debug; pub mod models; - pub trait GeoffreyDatabaseModel: Serialize + DeserializeOwned + Debug { fn id(&self) -> Option; fn set_id(&mut self, id: u64); diff --git a/geoffrey_models/src/models/db_metadata.rs b/geoffrey_models/src/models/db_metadata.rs index 6cf2798..936875c 100644 --- a/geoffrey_models/src/models/db_metadata.rs +++ b/geoffrey_models/src/models/db_metadata.rs @@ -1,5 +1,5 @@ -use serde::{Deserialize, Serialize}; use crate::GeoffreyDatabaseModel; +use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq)] pub struct DBMetadata { @@ -17,5 +17,3 @@ impl GeoffreyDatabaseModel for DBMetadata { "DBMetadata".to_string() } } - - diff --git a/geoffrey_models/src/models/locations/mod.rs b/geoffrey_models/src/models/locations/mod.rs index 5f97baa..4ff4ef4 100644 --- a/geoffrey_models/src/models/locations/mod.rs +++ b/geoffrey_models/src/models/locations/mod.rs @@ -6,7 +6,7 @@ use crate::models::locations::market::{Market, MarketDb}; use crate::models::locations::shop::Shop; use crate::models::locations::town::{Town, TownDb}; use crate::models::player::Player; -use crate::models::{Position, Portal}; +use crate::models::{Portal, Position}; use crate::GeoffreyDatabaseModel; use std::fmt::{Display, Formatter}; use std::str::FromStr; @@ -111,7 +111,7 @@ pub struct LocationDb { pub name: String, pub position: Position, owners: HashSet, - pub tunnel: Option, + pub portal: Option, pub loc_data: LocationDataDb, } @@ -131,7 +131,7 @@ impl LocationDb { name: name.to_string(), position, owners, - tunnel, + portal: tunnel, loc_data: loc_type, } } @@ -173,7 +173,7 @@ pub struct Location { pub name: String, pub position: Position, pub owners: Vec, - pub tunnel: Option, + pub portal: Option, pub loc_data: LocationData, } @@ -188,7 +188,7 @@ impl Location { name: location.name, position: location.position, owners, - tunnel: location.tunnel, + portal: location.portal, loc_data, } } @@ -228,7 +228,7 @@ mod tests { ); let l2 = LocationDb::new( "teSt", - Position::new(0, 0, 0,Dimension::Overworld), + Position::new(0, 0, 0, Dimension::Overworld), 0u64, None, LocationDataDb::Base, diff --git a/geoffrey_models/src/models/mod.rs b/geoffrey_models/src/models/mod.rs index 805b431..11bd4ca 100644 --- a/geoffrey_models/src/models/mod.rs +++ b/geoffrey_models/src/models/mod.rs @@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; use std::str::FromStr; +pub mod db_metadata; pub mod item; pub mod locations; pub mod meta; @@ -9,7 +10,6 @@ pub mod parameters; pub mod player; pub mod response; pub mod token; -pub mod db_metadata; #[derive(Serialize, Deserialize, Debug, Copy, Clone)] pub enum Dimension { @@ -86,40 +86,36 @@ impl Position { impl Display for Position { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "(x={}, y={}, z={}) {} ", self.x, self.y, self.z, self.dimension) + write!( + f, + "(x={}, y={}, z={}) {} ", + self.x, self.y, self.z, self.dimension + ) } } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Portal { x: i32, - z: i32 + z: i32, } impl Portal { pub fn new(x: i32, z: i32) -> Self { - Self { - x, - z - } + Self { x, z } } pub fn direction(&self) -> Direction { if self.x.abs() > self.z.abs() { if self.x < 0 { Direction::West - } - else { + } else { Direction::East } - } - else { - if self.z < 0 { - Direction::North - } - else { - Direction::South - } + } else if self.z < 0 { + Direction::North + } else { + Direction::South } } } diff --git a/geoffrey_models/src/models/parameters/add_location_params.rs b/geoffrey_models/src/models/parameters/add_location_params.rs index 752256d..cf9d168 100644 --- a/geoffrey_models/src/models/parameters/add_location_params.rs +++ b/geoffrey_models/src/models/parameters/add_location_params.rs @@ -1,7 +1,7 @@ use crate::models::locations::LocationType; use crate::models::parameters::CommandRequest; use crate::models::player::UserID; -use crate::models::{Position, Portal}; +use crate::models::{Portal, Position}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/geoffrey_models/src/models/parameters/mod.rs b/geoffrey_models/src/models/parameters/mod.rs index d484cd8..5ad2ba4 100644 --- a/geoffrey_models/src/models/parameters/mod.rs +++ b/geoffrey_models/src/models/parameters/mod.rs @@ -4,6 +4,7 @@ pub mod add_token_params; pub mod find_params; pub mod register_params; pub mod selling_params; +pub mod set_portal_params; use crate::models::player::{Player, UserID}; use crate::models::token::{Permissions, Token}; diff --git a/geoffrey_models/src/models/parameters/set_portal_params.rs b/geoffrey_models/src/models/parameters/set_portal_params.rs new file mode 100644 index 0000000..cd7609f --- /dev/null +++ b/geoffrey_models/src/models/parameters/set_portal_params.rs @@ -0,0 +1,41 @@ +use crate::models::parameters::CommandRequest; +use crate::models::player::UserID; +use crate::models::Portal; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct SetPortalParams { + pub token: String, + pub user_id: UserID, + pub loc_name: String, + pub portal: Portal, +} + +impl SetPortalParams { + pub fn new(loc_name: String, portal: Portal) -> Self { + Self { + token: Default::default(), + user_id: Default::default(), + loc_name, + portal, + } + } +} + +impl CommandRequest for SetPortalParams { + fn token(&self) -> String { + self.token.clone() + } + + fn user_id(&self) -> Option { + Some(self.user_id.clone()) + } + + fn set_user_id(&mut self, user_id: UserID) { + self.user_id = user_id; + } + + fn set_token(&mut self, token: String) { + self.token = token; + } +} diff --git a/geoffrey_models/src/models/response/selling_listing.rs b/geoffrey_models/src/models/response/selling_listing.rs index 006394e..a1d9bfe 100644 --- a/geoffrey_models/src/models/response/selling_listing.rs +++ b/geoffrey_models/src/models/response/selling_listing.rs @@ -1,5 +1,5 @@ use crate::models::item::ItemListing; -use crate::models::{Position, Portal}; +use crate::models::{Portal, Position}; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Clone)]