Added 'edit' commands
continuous-integration/woodpecker the build was successful Details

+ Allows a location's name or position to be updated
+ Added a bots commands for it, two for now as subcommands are not working right
+ Logging fix
+ Updated return messages for some bot commands
main
Joey Hines 2021-12-19 14:06:56 -07:00
parent 48be50dd67
commit 18a4373313
No known key found for this signature in database
GPG Key ID: 80F567B5C968F91B
25 changed files with 481 additions and 199 deletions

165
Cargo.lock generated
View File

@ -34,9 +34,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "async-trait"
version = "0.1.51"
version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e"
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
dependencies = [
"proc-macro2",
"quote",
@ -158,8 +158,8 @@ dependencies = [
"libc",
"num-integer",
"num-traits 0.2.14",
"serde 1.0.130",
"time 0.1.44",
"serde 1.0.132",
"time",
"winapi",
]
@ -198,7 +198,7 @@ dependencies = [
"lazy_static",
"nom",
"rust-ini",
"serde 1.0.130",
"serde 1.0.132",
"serde-hjson",
"serde_json",
"toml",
@ -273,9 +273,9 @@ dependencies = [
[[package]]
name = "encoding_rs"
version = "0.8.29"
version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746"
checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
dependencies = [
"cfg-if",
]
@ -335,9 +335,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
dependencies = [
"futures-channel",
"futures-core",
@ -349,9 +349,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
dependencies = [
"futures-core",
"futures-sink",
@ -359,33 +359,33 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
[[package]]
name = "futures-io"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
[[package]]
name = "futures-sink"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
[[package]]
name = "futures-task"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
[[package]]
name = "futures-util"
version = "0.3.18"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
dependencies = [
"futures-channel",
"futures-core",
@ -428,7 +428,7 @@ dependencies = [
"log",
"rand 0.8.4",
"regex",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
"simple_logger",
"structopt",
@ -445,7 +445,7 @@ dependencies = [
"geoffrey_models",
"log",
"reqwest",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
"serde_plain",
"serenity",
@ -463,9 +463,9 @@ dependencies = [
"json",
"lazy_static",
"log",
"serde 1.0.130",
"regex",
"serde 1.0.132",
"serde_json",
"simple_logger",
"sled",
]
@ -475,7 +475,7 @@ version = "0.1.0"
dependencies = [
"chrono",
"log",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
]
@ -503,9 +503,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.7"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55"
checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
dependencies = [
"bytes 1.1.0",
"fnv",
@ -577,7 +577,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [
"bytes 1.1.0",
"fnv",
"itoa",
"itoa 0.4.8",
]
[[package]]
@ -605,9 +605,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
[[package]]
name = "hyper"
version = "0.14.15"
version = "0.14.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
dependencies = [
"bytes 1.1.0",
"futures-channel",
@ -618,7 +618,7 @@ dependencies = [
"http-body",
"httparse",
"httpdate",
"itoa",
"itoa 0.4.8",
"pin-project-lite",
"socket2",
"tokio",
@ -637,7 +637,7 @@ dependencies = [
"hyper",
"rustls 0.20.2",
"tokio",
"tokio-rustls 0.23.1",
"tokio-rustls 0.23.2",
]
[[package]]
@ -704,6 +704,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "js-sys"
version = "0.3.55"
@ -740,9 +746,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.109"
version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01"
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]]
name = "linked-hash-map"
@ -933,9 +939,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "opaque-debug"
@ -965,9 +971,9 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.71"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
"autocfg",
"cc",
@ -1041,9 +1047,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.22"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "ppv-lite86"
@ -1077,9 +1083,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a"
checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
dependencies = [
"unicode-xid",
]
@ -1242,12 +1248,12 @@ dependencies = [
"pin-project-lite",
"rustls 0.20.2",
"rustls-pemfile",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"tokio-rustls 0.23.1",
"tokio-rustls 0.23.2",
"tokio-util",
"url",
"wasm-bindgen",
@ -1314,9 +1320,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.6"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "safemem"
@ -1397,9 +1403,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
[[package]]
name = "serde"
version = "1.0.130"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
dependencies = [
"serde_derive",
]
@ -1418,9 +1424,9 @@ dependencies = [
[[package]]
name = "serde_derive"
version = "1.0.130"
version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
dependencies = [
"proc-macro2",
"quote",
@ -1429,13 +1435,13 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.72"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
dependencies = [
"itoa",
"itoa 1.0.1",
"ryu",
"serde 1.0.130",
"serde 1.0.132",
]
[[package]]
@ -1444,7 +1450,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95455e7e29fada2052e72170af226fbe368a4ca33dee847875325d9fdb133858"
dependencies = [
"serde 1.0.130",
"serde 1.0.132",
]
[[package]]
@ -1454,15 +1460,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
dependencies = [
"form_urlencoded",
"itoa",
"itoa 0.4.8",
"ryu",
"serde 1.0.130",
"serde 1.0.132",
]
[[package]]
name = "serenity"
version = "0.10.9"
source = "git+https://github.com/serenity-rs/serenity.git#fe946df80ed725784ed5b6d5ee233fe82b896861"
source = "git+https://github.com/serenity-rs/serenity.git#04fc541b0e34d0e16c99039ce94cfe3cb79881b8"
dependencies = [
"async-trait",
"async-tungstenite",
@ -1474,7 +1480,7 @@ dependencies = [
"futures",
"percent-encoding",
"reqwest",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
"tokio",
"tracing",
@ -1506,14 +1512,13 @@ dependencies = [
[[package]]
name = "simple_logger"
version = "1.15.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "205596cf77a15774e5601c5ef759f4211ac381c0855a1f1d5e24a46f60f93e9a"
checksum = "45b60258a35dc3cb8a16890b8fd6723349bfa458d7960e25e633f1b1c19d7b5e"
dependencies = [
"atty",
"colored",
"log",
"time 0.3.5",
"winapi",
]
@ -1662,23 +1667,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "time"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad"
dependencies = [
"itoa",
"libc",
"time-macros",
]
[[package]]
name = "time-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
[[package]]
name = "tinyvec"
version = "1.5.1"
@ -1696,11 +1684,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.14.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144"
checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
dependencies = [
"autocfg",
"bytes 1.1.0",
"libc",
"memchr",
@ -1716,9 +1703,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
version = "1.6.0"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9efc1aba077437943f7515666aa2b882dfabfbfdf89c819ea75a8d6e9eaba5e"
checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7"
dependencies = [
"proc-macro2",
"quote",
@ -1748,9 +1735,9 @@ dependencies = [
[[package]]
name = "tokio-rustls"
version = "0.23.1"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689"
checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b"
dependencies = [
"rustls 0.20.2",
"tokio",
@ -1801,7 +1788,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde 1.0.130",
"serde 1.0.132",
]
[[package]]
@ -2021,7 +2008,7 @@ dependencies = [
"percent-encoding",
"pin-project",
"scoped-tls",
"serde 1.0.130",
"serde 1.0.132",
"serde_json",
"serde_urlencoded",
"tokio",

View File

@ -16,7 +16,12 @@ geoffrey_db = { path = "../geoffrey_db" }
config = "0.11.0"
structopt = "0.3.21"
log = "0.4.14"
simple_logger = "1.13.0"
rand = "0.8.4"
regex = "1.5.4"
chrono = { version = "0.4.19", features = ["serde"] }
# Doing this for now, as there seems to be an issue with using timestamps
[dependencies.simple_logger]
version = "1.16.0"
default-features = false
features = ["colors"]

View File

@ -1,9 +1,9 @@
use crate::commands::{Command, RequestType};
use crate::context::Context;
use crate::Result;
use geoffrey_db::helper::load_location;
use geoffrey_db::helper::{find_location_by_name_type, load_location};
use geoffrey_models::models::item::ItemListing;
use geoffrey_models::models::locations::{Location, LocationDataDb, LocationDb, LocationType};
use geoffrey_models::models::locations::{Location, LocationDataDb, LocationType};
use geoffrey_models::models::parameters::add_item_params::AddItemParams;
use geoffrey_models::models::player::Player;
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
@ -39,37 +39,21 @@ impl Command for AddItem {
fn run_command(ctx: Arc<Context>, req: &Self::Req, user: Option<Player>) -> Result<Self::Resp> {
let user = user.unwrap();
let shops: Vec<LocationDb> = ctx
.db
.filter(|_, loc: &LocationDb| {
let loc_type: LocationType = loc.loc_data.clone().into();
let mut shop =
find_location_by_name_type(&ctx.db, &req.shop, user.id.unwrap(), LocationType::Shop)?;
loc_type == LocationType::Shop
&& loc.owners().contains(&user.id.unwrap())
&& loc.name.to_lowercase().contains(&req.shop.to_lowercase())
})?
.collect();
if let LocationDataDb::Shop(shop_data) = &mut shop.loc_data {
shop_data.item_listings.insert(ItemListing::new(
&req.item_name,
req.price,
req.quantity,
));
if shops.is_empty() {
Err(GeoffreyAPIError::EntryNotFound)
} else if shops.len() > 1 {
Err(GeoffreyAPIError::MultipleLocationsMatch)
let shop = ctx.db.insert(shop)?;
load_location(&ctx.db, &shop).map_err(|err| err.into())
} else {
let mut shop = shops[0].clone();
if let LocationDataDb::Shop(shop_data) = &mut shop.loc_data {
shop_data.item_listings.insert(ItemListing::new(
&req.item_name,
req.price,
req.quantity,
));
let shop = ctx.db.insert(shop)?;
load_location(&ctx.db, &shop).map_err(|err| err.into())
} else {
Err(GeoffreyAPIError::EntryNotFound)
}
Err(GeoffreyAPIError::EntryNotFound)
}
}
}

View File

@ -1,7 +1,7 @@
use crate::commands::{Command, RequestType};
use crate::context::Context;
use crate::Result;
use geoffrey_db::helper::load_location;
use geoffrey_db::helper::{find_location_by_name, load_location};
use geoffrey_models::models::locations::{Location, LocationDb};
use geoffrey_models::models::parameters::delete_params::DeleteParams;
use geoffrey_models::models::player::Player;
@ -29,16 +29,8 @@ impl Command for Delete {
fn run_command(ctx: Arc<Context>, req: &Self::Req, user: Option<Player>) -> Result<Self::Resp> {
let user = user.unwrap();
let filter = regex::Regex::new(format!(r"(?i)^{}$", req.location).as_str()).unwrap();
let location: LocationDb = ctx
.db
.filter(|_, loc: &LocationDb| {
filter.is_match(&loc.name) && loc.owners().contains(&user.id.unwrap())
})?
.next()
.ok_or(GeoffreyAPIError::EntryNotFound)?;
let location = find_location_by_name(&ctx.db, &req.location, user.id.unwrap())?;
let location = load_location(&ctx.db, &location).map_err(GeoffreyAPIError::from)?;
ctx.db.remove::<LocationDb>(location.id)?;

View File

@ -0,0 +1,46 @@
use crate::commands::{Command, RequestType};
use crate::context::Context;
use crate::Result;
use geoffrey_db::helper::{find_location_by_name, load_location};
use geoffrey_models::models::locations::Location;
use geoffrey_models::models::parameters::edit_params::EditParams;
use geoffrey_models::models::player::Player;
use geoffrey_models::models::CommandLevel;
use std::sync::Arc;
pub struct Edit {}
impl Command for Edit {
type Req = EditParams;
type Resp = Location;
fn command_name() -> String {
"edit".to_string()
}
fn request_type() -> RequestType {
RequestType::POST
}
fn command_level() -> CommandLevel {
CommandLevel::REGISTERED
}
fn run_command(ctx: Arc<Context>, req: &Self::Req, user: Option<Player>) -> Result<Self::Resp> {
let user = user.unwrap();
let mut location = find_location_by_name(&ctx.db, &req.loc_name, user.id.unwrap())?;
if let Some(new_pos) = &req.new_pos {
location.position = *new_pos;
}
if let Some(new_name) = &req.new_name {
location.name = new_name.clone();
}
let location = ctx.db.insert(location)?;
load_location(&ctx.db, &location).map_err(|err| err.into())
}
}

View File

@ -1,6 +1,7 @@
use crate::commands::add_item::AddItem;
use crate::commands::add_location::AddLocation;
use crate::commands::delete::Delete;
use crate::commands::edit::Edit;
use crate::commands::find::FindCommand;
use crate::commands::link::LinkCommand;
use crate::commands::register::Register;
@ -26,6 +27,7 @@ pub mod add_item;
pub mod add_location;
pub mod add_token;
pub mod delete;
pub mod edit;
pub mod find;
pub mod link;
pub mod register;
@ -134,6 +136,7 @@ pub fn command_filter(
.or(create_command_filter::<AddItem>(ctx.clone()))
.or(create_command_filter::<Delete>(ctx.clone()))
.or(create_command_filter::<LinkCommand>(ctx.clone()))
.or(create_command_filter::<Edit>(ctx.clone()))
.or(create_command_filter::<SetPortal>(ctx)),
)
}

View File

@ -1,11 +1,10 @@
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_db::helper::{find_location_by_name, load_location};
use geoffrey_models::models::locations::Location;
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;
@ -29,15 +28,8 @@ impl Command for SetPortal {
fn run_command(ctx: Arc<Context>, req: &Self::Req, user: Option<Player>) -> Result<Self::Resp> {
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)?;
let mut location = find_location_by_name(&ctx.db, &req.loc_name, user.id.unwrap())?;
location.portal = Some(req.portal.clone());

View File

@ -17,4 +17,9 @@ async-trait = "0.1.51"
config = "0.11.0"
structopt = "0.3.21"
log = "0.4.14"
simple_logger = "1.13.0"
# Doing this for now, as there seems to be an issue with using timestamps
[dependencies.simple_logger]
version = "1.16.0"
default-features = false
features = ["colors"]

View File

@ -2,8 +2,10 @@ use crate::bot::commands::CommandError;
use geoffrey_models::models::locations::LocationType;
use geoffrey_models::models::parameters::selling_params::{ItemSort, Order};
use geoffrey_models::models::Dimension;
use serenity::builder::CreateApplicationCommandOption;
use serenity::model::prelude::application_command::{
ApplicationCommandInteractionDataOption, ApplicationCommandInteractionDataOptionValue,
ApplicationCommandOptionType,
};
use std::str::FromStr;
@ -70,3 +72,52 @@ pub fn option_to_order(
Order::from_str(&loc_type).map_err(|_| CommandError::ArgumentParse(field.to_string()))
}
pub fn add_x_position_argument(
option: &mut CreateApplicationCommandOption,
) -> &mut CreateApplicationCommandOption {
option
.name("x")
.description("X coordinate")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
}
pub fn add_y_position_argument(
option: &mut CreateApplicationCommandOption,
) -> &mut CreateApplicationCommandOption {
option
.name("y")
.description("Y Coordinate")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
}
pub fn add_z_position_argument(
option: &mut CreateApplicationCommandOption,
) -> &mut CreateApplicationCommandOption {
option
.name("z")
.description("Z Coordinate")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
}
pub fn add_dimension_argument(
option: &mut CreateApplicationCommandOption,
) -> &mut CreateApplicationCommandOption {
option
.name("dimension")
.description("Dimension of the shop, default is Overworld")
.kind(ApplicationCommandOptionType::String)
.add_string_choice(Dimension::Overworld, Dimension::Overworld)
.add_string_choice(Dimension::Nether, Dimension::Nether)
.add_string_choice(Dimension::TheEnd, Dimension::TheEnd)
.required(false)
}

View File

@ -9,6 +9,7 @@ use geoffrey_models::models::parameters::add_item_params::AddItemParams;
use crate::bot::arg_parse::{option_to_i64, option_to_string};
use crate::bot::commands::{BotCommand, CommandError};
use crate::bot::formatters::display_loc;
use crate::bot::lang::{PLAYER_ALREADY_SELLS_ITEM, PLAYER_DOES_NOT_HAVE_MATCHING_SHOP};
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
use serenity::builder::CreateApplicationCommand;
@ -90,6 +91,10 @@ impl BotCommand for AddItemCommand {
}
fn build_response(resp: Self::ApiResp) -> String {
format!("{} has been updated", resp.name)
format!(
"**{}** has been updated:\n{}",
resp.name,
display_loc(&resp)
)
}
}

View File

@ -7,8 +7,12 @@ use serenity::model::interactions::application_command::{
ApplicationCommandInteraction, ApplicationCommandOptionType,
};
use crate::bot::arg_parse::{option_to_dim, option_to_i64, option_to_loc_type, option_to_string};
use crate::bot::arg_parse::{
add_dimension_argument, add_x_position_argument, add_y_position_argument,
add_z_position_argument, option_to_dim, option_to_i64, option_to_loc_type, option_to_string,
};
use crate::bot::commands::{BotCommand, CommandError};
use crate::bot::formatters::display_loc;
use serenity::builder::CreateApplicationCommand;
pub struct AddLocationCommand;
@ -50,43 +54,10 @@ impl BotCommand for AddLocationCommand {
.kind(ApplicationCommandOptionType::String)
.required(true)
})
.create_option(|option| {
option
.name("x")
.description("X coordinate of the location")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
})
.create_option(|option| {
option
.name("y")
.description("Y coordinate of the location")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
})
.create_option(|option| {
option
.name("z")
.description("Z coordinate of the location")
.kind(ApplicationCommandOptionType::Integer)
.max_int_value(i32::MAX)
.min_int_value(i32::MIN)
.required(true)
})
.create_option(|option| {
option
.name("dimension")
.description("Dimension of the shop, default is Overworld")
.kind(ApplicationCommandOptionType::String)
.add_string_choice(Dimension::Overworld, Dimension::Overworld)
.add_string_choice(Dimension::Nether, Dimension::Nether)
.add_string_choice(Dimension::TheEnd, Dimension::TheEnd)
.required(false)
})
.create_option(add_x_position_argument)
.create_option(add_y_position_argument)
.create_option(add_z_position_argument)
.create_option(add_dimension_argument)
}
async fn process_arguments(
@ -106,6 +77,10 @@ impl BotCommand for AddLocationCommand {
}
fn build_response(resp: Self::ApiResp) -> String {
format!("{} has been added to Geoffrey.", resp.name)
format!(
"**{}** has been added to Geoffrey:\n{}",
resp.name,
display_loc(&resp)
)
}
}

View File

@ -60,7 +60,7 @@ impl BotCommand for DeleteCommand {
fn build_response(resp: Self::ApiResp) -> String {
format!(
"{} has been been removed from Geoffrey, good riddance!",
"**{}** has been been removed from Geoffrey, good riddance!",
resp.name
)
}

View File

@ -0,0 +1,70 @@
use async_trait::async_trait;
use geoffrey_models::models::locations::Location;
use reqwest::Method;
use serenity::model::interactions::application_command::{
ApplicationCommandInteraction, ApplicationCommandOptionType,
};
use crate::bot::arg_parse::option_to_string;
use crate::bot::commands::{BotCommand, CommandError};
use crate::bot::formatters::display_loc;
use geoffrey_models::models::parameters::edit_params::EditParams;
use serenity::builder::CreateApplicationCommand;
//TODO: Combine edit commands into one class once I figure out why subcommand are not working
pub struct EditNameCommand;
#[async_trait]
impl BotCommand for EditNameCommand {
type ApiParams = EditParams;
type ApiResp = Location;
fn command_name() -> String {
"edit_name".to_string()
}
fn endpoint_name() -> String {
"edit".to_string()
}
fn request_type() -> Method {
Method::POST
}
fn create_app_command(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
command
.name(Self::command_name())
.description("Edit a location's name")
.create_option(|option| {
option
.name("loc_name")
.description("Location to edit")
.kind(ApplicationCommandOptionType::String)
.required(true)
})
.create_option(|option| {
option
.name("new_name")
.description("New location name")
.kind(ApplicationCommandOptionType::String)
.required(true)
})
}
async fn process_arguments(
command_interaction: ApplicationCommandInteraction,
) -> Result<Self::ApiParams, CommandError> {
let options = command_interaction.data.options;
let name = option_to_string(options.get(0), "loc_name")?;
let new_name = option_to_string(options.get(1), "new_name")?;
Ok(Self::ApiParams::new(name, None, Some(new_name)))
}
fn build_response(resp: Self::ApiResp) -> String {
format!(
"**{}** has been updated:\n{}",
resp.name,
display_loc(&resp)
)
}
}

View File

@ -0,0 +1,77 @@
use async_trait::async_trait;
use geoffrey_models::models::locations::Location;
use geoffrey_models::models::{Dimension, Position};
use reqwest::Method;
use serenity::model::interactions::application_command::{
ApplicationCommandInteraction, ApplicationCommandOptionType,
};
use crate::bot::arg_parse::{
add_dimension_argument, add_x_position_argument, add_y_position_argument,
add_z_position_argument, option_to_dim, option_to_i64, option_to_string,
};
use crate::bot::commands::{BotCommand, CommandError};
use crate::bot::formatters::display_loc;
use geoffrey_models::models::parameters::edit_params::EditParams;
use serenity::builder::CreateApplicationCommand;
//TODO: Combine edit commands into one class once I figure out why subcommand are not working
pub struct EditPosCommand;
#[async_trait]
impl BotCommand for EditPosCommand {
type ApiParams = EditParams;
type ApiResp = Location;
fn command_name() -> String {
"edit_pos".to_string()
}
fn endpoint_name() -> String {
"edit".to_string()
}
fn request_type() -> Method {
Method::POST
}
fn create_app_command(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
command
.name(Self::command_name())
.description("Edit a location's position")
.create_option(|option| {
option
.name("loc_name")
.description("Location to edit")
.kind(ApplicationCommandOptionType::String)
.required(true)
})
.create_option(add_x_position_argument)
.create_option(add_y_position_argument)
.create_option(add_z_position_argument)
.create_option(add_dimension_argument)
}
async fn process_arguments(
command_interaction: ApplicationCommandInteraction,
) -> Result<Self::ApiParams, CommandError> {
let options = command_interaction.data.options;
let name = option_to_string(options.get(0), "loc_name")?;
let x = option_to_i64(options.get(1), "x")?;
let y = option_to_i64(options.get(2), "y")?;
let z = option_to_i64(options.get(3), "z")?;
let dim = option_to_dim(options.get(4), "dimension").unwrap_or(Dimension::Overworld);
let position = Position::new(x as i32, y as i32, z as i32, dim);
Ok(Self::ApiParams::new(name, Some(position), None))
}
fn build_response(resp: Self::ApiResp) -> String {
format!(
"**{}** has been updated:\n{}",
resp.name,
display_loc(&resp)
)
}
}

View File

@ -57,7 +57,7 @@ impl BotCommand for FindCommand {
let mut resp_str = String::new();
writeln!(resp_str, "The following locations match:").unwrap();
for loc in resp {
writeln!(resp_str, "{}", display_loc(loc)).unwrap();
writeln!(resp_str, "{}", display_loc(&loc)).unwrap();
}
resp_str
}

View File

@ -20,6 +20,8 @@ use std::pin::Pin;
pub mod add_item;
pub mod add_location;
pub mod delete;
pub mod edit_name;
pub mod edit_pos;
pub mod find;
pub mod register;
pub mod selling;
@ -81,12 +83,16 @@ pub trait BotCommand: Send + 'static {
fn command_name() -> String;
fn endpoint_name() -> String {
Self::command_name()
}
fn request_type() -> reqwest::Method;
fn command_url(base_string: &str) -> String {
let slash = if !base_string.ends_with('/') { "/" } else { "" };
format!("{}{}command/{}/", base_string, slash, Self::command_name())
format!("{}{}command/{}/", base_string, slash, Self::endpoint_name())
}
async fn run_api_query(

View File

@ -8,6 +8,7 @@ use serenity::model::interactions::application_command::{
use crate::bot::arg_parse::{option_to_i64, option_to_string};
use crate::bot::commands::{BotCommand, CommandError};
use crate::bot::formatters::display_loc;
use crate::bot::lang::PLAYER_DOES_NOT_HAVE_MATCHING_LOC;
use geoffrey_models::models::parameters::set_portal_params::SetPortalParams;
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
@ -82,6 +83,10 @@ impl BotCommand for SetPortalCommand {
}
fn build_response(resp: Self::ApiResp) -> String {
format!("{} has been been updated.", resp.name)
format!(
"**{}** has been updated:\n{}",
resp.name,
display_loc(&resp)
)
}
}

View File

@ -2,7 +2,7 @@ use geoffrey_models::models::locations::Location;
use geoffrey_models::models::player::Player;
use geoffrey_models::models::Portal;
pub fn display_owners(owners: Vec<Player>, limit: usize) -> String {
pub fn display_owners(owners: &[Player], limit: usize) -> String {
let mut plural = "";
let mut ellipses = "";
@ -29,7 +29,7 @@ pub fn display_owners(owners: Vec<Player>, limit: usize) -> String {
)
}
pub fn display_portal(portal: Portal) -> String {
pub fn display_portal(portal: &Portal) -> String {
format!(
"Portal: {} {} (x={}, z={})",
portal.direction(),
@ -39,8 +39,8 @@ pub fn display_portal(portal: Portal) -> String {
)
}
pub fn display_loc(loc: Location) -> String {
let portal_str = match loc.portal {
pub fn display_loc(loc: &Location) -> String {
let portal_str = match &loc.portal {
None => "".to_string(),
Some(p) => format!("{}, ", display_portal(p)),
};
@ -50,6 +50,6 @@ pub fn display_loc(loc: Location) -> String {
loc.name,
loc.position,
portal_str,
display_owners(loc.owners, 3),
display_owners(&loc.owners, 3),
)
}

View File

@ -2,6 +2,8 @@ use serenity::model::interactions::application_command::ApplicationCommand;
use serenity::prelude::*;
use crate::bot::commands::delete::DeleteCommand;
use crate::bot::commands::edit_name::EditNameCommand;
use crate::bot::commands::edit_pos::EditPosCommand;
use crate::bot::commands::register::RegisterCommand;
use crate::bot::commands::GeoffreyCommandFn;
use crate::context::GeoffreyContext;
@ -23,15 +25,21 @@ mod lang;
#[derive(Default)]
pub struct CommandRunner {
commands: HashMap<String, GeoffreyCommandFn>,
pub app_commands: Vec<ApplicationCommand>,
}
impl CommandRunner {
async fn register_app_command<T: BotCommand>(ctx: &Context) -> Result<(), CommandError> {
ApplicationCommand::create_global_application_command(&ctx.http, |command| {
async fn register_app_command<T: BotCommand>(
&mut self,
ctx: &Context,
) -> Result<(), CommandError> {
let command = ApplicationCommand::create_global_application_command(&ctx.http, |command| {
T::create_app_command(command)
})
.await?;
self.app_commands.push(command);
Ok(())
}
@ -45,7 +53,7 @@ impl CommandRunner {
ctx: &Context,
) -> Result<&mut Self, CommandError> {
self.add_command_to_lookup::<T>();
Self::register_app_command::<T>(ctx).await?;
self.register_app_command::<T>(ctx).await?;
Ok(self)
}
@ -83,6 +91,10 @@ pub async fn build_commands(
.add_command::<DeleteCommand>(ctx)
.await?
.add_command::<RegisterCommand>(ctx)
.await?
.add_command::<EditPosCommand>(ctx)
.await?
.add_command::<EditNameCommand>(ctx)
.await?;
Ok(())

View File

@ -56,11 +56,17 @@ impl EventHandler for Handler {
.expect("Unable to open command runner!");
match build_commands(&ctx, command_runner).await {
Ok(_) => {}
Ok(_) => {
log::debug!("Registered the following commands:");
for command in &command_runner.app_commands {
log::debug!("{:?}", command)
}
}
Err(e) => {
log::warn!("Error registering commands: {:?}", e)
}
}
log::info!("Init completed.");
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {

View File

@ -13,8 +13,8 @@ serde_json = "1.0"
geoffrey_models = { path = "../geoffrey_models" }
byteorder = "1.4.2"
log = "0.4.14"
simple_logger = "1.13.0"
json = "0.12.4"
regex = "1.5.4"
[dev-dependencies]
lazy_static = "1.4.0"

View File

@ -1,8 +1,10 @@
use crate::database::Database;
use crate::error::Result;
use crate::error::{GeoffreyDBError, Result};
use geoffrey_models::models::locations::market::Market;
use geoffrey_models::models::locations::town::Town;
use geoffrey_models::models::locations::{Location, LocationData, LocationDataDb, LocationDb};
use geoffrey_models::models::locations::{
Location, LocationData, LocationDataDb, LocationDb, LocationType,
};
use geoffrey_models::models::player::Player;
pub fn load_location_data(db: &Database, data: &LocationDataDb) -> Result<LocationData> {
@ -48,3 +50,39 @@ pub fn load_location(db: &Database, location: &LocationDb) -> Result<Location> {
loc_data,
))
}
pub fn find_location_by_name(
db: &Database,
location_name: &str,
owner_id: u64,
) -> Result<LocationDb> {
let filter = regex::Regex::new(format!(r"(?i)^{}$", location_name).as_str()).unwrap();
let location: LocationDb = db
.filter(|_, loc: &LocationDb| {
loc.owners().contains(&owner_id) && filter.is_match(loc.name.as_str())
})?
.next()
.ok_or(GeoffreyDBError::NotFound)?;
Ok(location)
}
pub fn find_location_by_name_type(
db: &Database,
location_name: &str,
owner_id: u64,
loc_type: LocationType,
) -> Result<LocationDb> {
let filter = regex::Regex::new(format!(r"(?i)^{}$", location_name).as_str()).unwrap();
let location: LocationDb = db
.filter(|_, loc: &LocationDb| {
let lt: LocationType = loc.loc_data.clone().into();
loc.owners().contains(&owner_id) && filter.is_match(loc.name.as_str()) && lt == loc_type
})?
.next()
.ok_or(GeoffreyDBError::NotFound)?;
Ok(location)
}

View File

@ -10,4 +10,4 @@ edition = "2018"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4.19", features = ["serde"] }
log = "0.4.14"
log = "0.4.14"

View File

@ -0,0 +1,22 @@
use crate::models::parameters::GeoffreyParam;
use crate::models::Position;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EditParams {
pub loc_name: String,
pub new_pos: Option<Position>,
pub new_name: Option<String>,
}
impl EditParams {
pub fn new(loc_name: String, new_pos: Option<Position>, new_name: Option<String>) -> Self {
Self {
loc_name,
new_pos,
new_name,
}
}
}
impl GeoffreyParam for EditParams {}

View File

@ -2,6 +2,7 @@ pub mod add_item_params;
pub mod add_location_params;
pub mod add_token_params;
pub mod delete_params;
pub mod edit_params;
pub mod find_params;
pub mod link_params;
pub mod register_params;