From 292cedaa3462f7532efda98722354afa8e213b6a Mon Sep 17 00:00:00 2001 From: acdenisSK Date: Tue, 24 Oct 2017 18:05:25 +0200 Subject: Fall back to `str::parse` if `parse_username` fails --- src/model/misc.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/model/misc.rs b/src/model/misc.rs index af49a76..625e202 100644 --- a/src/model/misc.rs +++ b/src/model/misc.rs @@ -125,9 +125,10 @@ impl FromStr for UserId { type Err = UserIdParseError; fn from_str(s: &str) -> StdResult { - utils::parse_username(s) - .ok_or_else(|| UserIdParseError::InvalidFormat) - .map(UserId) + Ok(match utils::parse_username(s) { + Some(id) => UserId(id), + None => s.parse::().map(UserId).map_err(|_| UserIdParseError::InvalidFormat)?, + }) } } -- cgit v1.2.3 From e694766bb6c93d5f6a75ad9871cfdefbd0309a17 Mon Sep 17 00:00:00 2001 From: Uninteresting Account Date: Sun, 29 Oct 2017 18:27:38 +1000 Subject: Fix #206 (#207) --- .gitignore | 6 +++++- src/framework/standard/command.rs | 37 +++++++++++++++++++++++++++---------- src/framework/standard/mod.rs | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 5f76dbe..af3b590 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,8 @@ target/ Cargo.lock -.vscode/ \ No newline at end of file +.vscode/ + +.idea/ + +*.iml diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs index 6330810..b53ed90 100644 --- a/src/framework/standard/command.rs +++ b/src/framework/standard/command.rs @@ -131,6 +131,7 @@ pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Opti if let Some(mention_end) = find_mention_end(&msg.content, conf) { positions.push(mention_end); + return Some(positions); } else if let Some(ref func) = conf.dynamic_prefix { if let Some(x) = func(ctx, msg) { if msg.content.starts_with(&x) { @@ -155,22 +156,18 @@ pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Opti return None; } - if conf.allow_whitespace { - let pos = *unsafe { positions.get_unchecked(0) }; + let pos = *unsafe { positions.get_unchecked(0) }; - positions.insert(0, pos + 1); + if conf.allow_whitespace { + positions.insert(0, find_end_of_prefix_with_whitespace(&msg.content, pos).unwrap_or(pos)); + } else if find_end_of_prefix_with_whitespace(&msg.content, pos).is_some() { + return None; } Some(positions) } else if conf.on_mention.is_some() { find_mention_end(&msg.content, conf).map(|mention_end| { - let mut positions = vec![mention_end]; - - if conf.allow_whitespace { - positions.insert(0, mention_end + 1); - } - - positions + vec![mention_end] // This can simply be returned without trying to find the end whitespaces as trim will remove it later }) } else { None @@ -185,3 +182,23 @@ fn find_mention_end(content: &str, conf: &Configuration) -> Option { .map(|m| m.len()) }) } + +// Finds the end of the first continuous block of whitespace after the prefix +fn find_end_of_prefix_with_whitespace(content: &str, position: usize) -> Option { + let mut ws_split = content.split_whitespace(); + if let Some(cmd) = ws_split.nth(1) { + if let Some(index_of_cmd) = content.find(cmd) { + if index_of_cmd > position && index_of_cmd <= content.len() { + let slice = unsafe { content.slice_unchecked(position, index_of_cmd) }.as_bytes(); + for byte in slice.iter() { + // 0x20 is ASCII for space + if *byte != 0x20u8 { + return None; + } + } + return Some(index_of_cmd); + } + } + } + None +} diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index 1a7a5ee..f4c98e8 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -860,7 +860,7 @@ impl Framework for StandardFramework { 'outer: for position in positions { let mut built = String::new(); let round = message.content.chars().skip(position).collect::(); - let round = round.trim().split_whitespace().collect::>(); + let round = round.trim().split_whitespace().collect::>(); // Call to `trim` causes the related bug under the main bug #206 - where the whitespace settings are ignored. The fix is implemented as an additional check inside command::positions for i in 0..self.configuration.depth { if i != 0 { -- cgit v1.2.3 From d50b12931404946e219d3ff0878f0632445ef35f Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sun, 29 Oct 2017 09:53:10 -0700 Subject: Add logging and dotenv to example 07 --- .gitignore | 1 + examples/07_sample_bot_structure/.env.example | 10 ++++++++ examples/07_sample_bot_structure/Cargo.toml | 5 ++++ examples/07_sample_bot_structure/src/main.rs | 35 +++++++++++++++++++++++---- 4 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 examples/07_sample_bot_structure/.env.example diff --git a/.gitignore b/.gitignore index af3b590..721444a 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ Cargo.lock .idea/ *.iml +.env diff --git a/examples/07_sample_bot_structure/.env.example b/examples/07_sample_bot_structure/.env.example new file mode 100644 index 0000000..3b3b4ac --- /dev/null +++ b/examples/07_sample_bot_structure/.env.example @@ -0,0 +1,10 @@ +# This declares an environment variable named "DISCORD_TOKEN" with the given +# value. When calling `kankyo::load()`, it will read the `.env` file and parse +# these key-value pairs and insert them into the environment. +# +# Environment variables are separated by newlines and must not have space +# around the equals sign (`=`). +DISCORD_TOKEN=put your token here +# Declares the level of logging to use. Read the documentation for the `log` +# and `env_logger` crates for more information. +RUST_LOG=debug diff --git a/examples/07_sample_bot_structure/Cargo.toml b/examples/07_sample_bot_structure/Cargo.toml index 0bebb46..b1dba53 100644 --- a/examples/07_sample_bot_structure/Cargo.toml +++ b/examples/07_sample_bot_structure/Cargo.toml @@ -3,6 +3,11 @@ name = "07_sample_bot_structure" version = "0.1.0" authors = ["my name "] +[dependencies] +env_logger = "~0.4" +kankyo = "~0.1" +log = "~0.3" + [dependencies.serenity] features = ["cache", "framework", "standard_framework"] path = "../../" diff --git a/examples/07_sample_bot_structure/src/main.rs b/examples/07_sample_bot_structure/src/main.rs index 8962d55..01f7a61 100644 --- a/examples/07_sample_bot_structure/src/main.rs +++ b/examples/07_sample_bot_structure/src/main.rs @@ -9,18 +9,43 @@ //! features = ["framework", "standard_framework"] //! ``` -#[macro_use] -extern crate serenity; +#[macro_use] extern crate log; +#[macro_use] extern crate serenity; + +extern crate env_logger; +extern crate kankyo; mod commands; -use serenity::prelude::*; use serenity::framework::StandardFramework; +use serenity::model::event::ResumedEvent; +use serenity::model::Ready; +use serenity::prelude::*; use std::env; -struct Handler; impl EventHandler for Handler {} +struct Handler; + +impl EventHandler for Handler { + fn on_ready(&self, _: Context, ready: Ready) { + info!("Connected as {}", ready.user.name); + } + + fn on_resume(&self, _: Context, _: ResumedEvent) { + info!("Resumed"); + } +} fn main() { + // This will load the environment variables located at `./.env`, relative to + // the CWD. See `./.env.example` for an example on how to structure this. + kankyo::load().expect("Failed to load .env file"); + + // Initialize the logger to use environment variables. + // + // In this case, a good default is setting the environment variable + // `RUST_LOG` to debug`. + env_logger::init().expect("Failed to initialize env_logger"); + let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap(), Handler); client.with_framework(StandardFramework::new() @@ -30,6 +55,6 @@ fn main() { .command("multiply", |c| c.exec(commands::math::multiply))); if let Err(why) = client.start() { - println!("Client error: {:?}", why); + error!("Client error: {:?}", why); } } -- cgit v1.2.3 From 361658510f3e2eb9aefbe66232b9b1f1a1ebb80f Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sun, 29 Oct 2017 11:52:54 -0700 Subject: Fix shard shutdown via Context This fixes the shard shutdown via the Context. This works by setting a "shutdown" field on the Shard struct as being true, indicating that the Shard has shutdown. The Shard Runner detects this and requests a shutdown from the Shard Manager. The ideal solution here would be to add a "Shutdown" variant to serenity::gateway::ConnectionStage, but that would be a breaking change, so we instead need to opt for adding a new struct to gateway::Shard. The Shard Manager has also been updated to only attempt the shutdown of a shard if it doesn't already know for certain that it shut itself down, which avoids an error logged saying that there was an error sending a shutdown message to its Shard Runner. When all shards have been shutdown (for most bots, this will only be one), the Shard Manager will end and the Client will stop its operations, returning thread control to the user. --- src/client/bridge/gateway/shard_manager.rs | 14 +++++++++----- src/client/bridge/gateway/shard_runner.rs | 19 +++++++++++++++++-- src/gateway/mod.rs | 2 +- src/gateway/shard.rs | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/client/bridge/gateway/shard_manager.rs b/src/client/bridge/gateway/shard_manager.rs index 98ada1e..dfd4a16 100644 --- a/src/client/bridge/gateway/shard_manager.rs +++ b/src/client/bridge/gateway/shard_manager.rs @@ -174,13 +174,17 @@ impl ShardManager { } fn shutdown(&mut self, shard_id: ShardId) { - info!("Shutting down shard {}", shard_id); - if let Some(runner) = self.runners.lock().get(&shard_id) { - let msg = ShardManagerMessage::Shutdown(shard_id); + let is_shutdown = runner.shard.lock().is_shutdown(); + + if !is_shutdown { + info!("Shutting down shard {}", shard_id); + + let msg = ShardManagerMessage::Shutdown(shard_id); - if let Err(why) = runner.runner_tx.send(msg) { - warn!("Failed to cleanly shutdown shard {}: {:?}", shard_id, why); + if let Err(why) = runner.runner_tx.send(msg) { + warn!("Failed to cleanly shutdown shard {}: {:?}", shard_id, why); + } } } diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs index 7ee18c3..aa0e064 100644 --- a/src/client/bridge/gateway/shard_runner.rs +++ b/src/client/bridge/gateway/shard_runner.rs @@ -140,8 +140,16 @@ impl ShardRunner { }} } - if !successful && !self.shard.lock().stage().is_connecting() { - return self.request_restart(); + { + let shard = self.shard.lock(); + + if !successful && !shard.stage().is_connecting() { + return self.request_restart(); + } + + if shard.is_shutdown() { + return self.request_shutdown(); + } } } } @@ -219,4 +227,11 @@ impl ShardRunner { Ok(()) } + + fn request_shutdown(&self) -> Result<()> { + debug!("[ShardRunner {:?}] Requesting shutdown", self.shard_info); + let _ = self.manager_tx.send(ShardManagerMessage::ShutdownAll); + + Ok(()) + } } diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index b593f5c..ed54bca 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -132,7 +132,7 @@ impl ConnectionStage { match *self { Connecting | Handshake | Identifying | Resuming => true, - _ => false, + Connected | Disconnected => false, } } } diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index 3a8209d..e5fe65d 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -89,6 +89,8 @@ pub struct Shard { seq: u64, session_id: Option, shard_info: [u64; 2], + /// Whether the shard has permanently shutdown. + shutdown: bool, stage: ConnectionStage, token: Arc>, ws_url: Arc>, @@ -144,6 +146,7 @@ impl Shard { let user = http::get_current_user()?; Shard { + shutdown: false, client, current_presence, heartbeat_instants, @@ -160,6 +163,7 @@ impl Shard { } } else { Shard { + shutdown: false, client, current_presence, heartbeat_instants, @@ -176,6 +180,18 @@ impl Shard { }) } + /// Whether the shard has permanently shutdown. + /// + /// This should normally happen due to manual calling of [`shutdown`] or + /// [`shutdown_clean`]. + /// + /// [`shutdown`]: #method.shutdown + /// [`shutdown_clean`]: #method.shutdown_clean + #[inline] + pub fn is_shutdown(&self) -> bool { + self.shutdown + } + /// Retrieves a copy of the current shard information. /// /// The first element is the _current_ shard - 0-indexed - while the second @@ -604,6 +620,7 @@ impl Shard { stream.flush()?; stream.shutdown(Shutdown::Both)?; + self.shutdown = true; debug!("[Shard {:?}] Cleanly shutdown shard", self.shard_info); Ok(()) @@ -616,6 +633,8 @@ impl Shard { stream.flush()?; stream.shutdown(Shutdown::Both)?; + self.shutdown = true; + Ok(()) } -- cgit v1.2.3 From 41f26b3757c7a5fba1f09f34e3192e2fd9702a4a Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sun, 29 Oct 2017 11:56:25 -0700 Subject: Add owner + quit functionality to example 07 --- .../07_sample_bot_structure/src/commands/mod.rs | 1 + .../07_sample_bot_structure/src/commands/owner.rs | 10 ++++++++++ examples/07_sample_bot_structure/src/main.rs | 21 +++++++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 examples/07_sample_bot_structure/src/commands/owner.rs diff --git a/examples/07_sample_bot_structure/src/commands/mod.rs b/examples/07_sample_bot_structure/src/commands/mod.rs index bf58dba..9c5dfaa 100644 --- a/examples/07_sample_bot_structure/src/commands/mod.rs +++ b/examples/07_sample_bot_structure/src/commands/mod.rs @@ -1,2 +1,3 @@ pub mod math; pub mod meta; +pub mod owner; diff --git a/examples/07_sample_bot_structure/src/commands/owner.rs b/examples/07_sample_bot_structure/src/commands/owner.rs new file mode 100644 index 0000000..e80c19d --- /dev/null +++ b/examples/07_sample_bot_structure/src/commands/owner.rs @@ -0,0 +1,10 @@ +command!(quit(ctx, msg, _args) { + match ctx.quit() { + Ok(()) => { + let _ = msg.reply("Shutting down!"); + }, + Err(why) => { + let _ = msg.reply(&format!("Failed to shutdown: {:?}", why)); + }, + } +}); diff --git a/examples/07_sample_bot_structure/src/main.rs b/examples/07_sample_bot_structure/src/main.rs index 01f7a61..37f6c98 100644 --- a/examples/07_sample_bot_structure/src/main.rs +++ b/examples/07_sample_bot_structure/src/main.rs @@ -21,6 +21,8 @@ use serenity::framework::StandardFramework; use serenity::model::event::ResumedEvent; use serenity::model::Ready; use serenity::prelude::*; +use serenity::http; +use std::collections::HashSet; use std::env; struct Handler; @@ -48,11 +50,26 @@ fn main() { let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap(), Handler); + let owners = match http::get_current_application_info() { + Ok(info) => { + let mut set = HashSet::new(); + set.insert(info.owner.id); + + set + }, + Err(why) => panic!("Couldn't get application info: {:?}", why), + }; + client.with_framework(StandardFramework::new() - .configure(|c| c.prefix("~")) + .configure(|c| c + .owners(owners) + .prefix("~")) .command("ping", |c| c.exec(commands::meta::ping)) .command("latency", |c| c.exec(commands::meta::latency)) - .command("multiply", |c| c.exec(commands::math::multiply))); + .command("multiply", |c| c.exec(commands::math::multiply)) + .command("quit", |c| c + .exec(commands::owner::quit) + .owners_only(true))); if let Err(why) = client.start() { error!("Client error: {:?}", why); -- cgit v1.2.3 From ce4f8c2ac8dd2c472ab537a60bf92579d078073b Mon Sep 17 00:00:00 2001 From: Mei Boudreau Date: Sun, 29 Oct 2017 15:39:39 -0400 Subject: Cleanup gitignore to have comments (#208) --- .gitignore | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 721444a..5f4b3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ +# IDE directories and folders +.vscode/ +.idea/ + +# Target directory target/ +# Lockfile Cargo.lock -.vscode/ - -.idea/ - +# Misc *.iml .env -- cgit v1.2.3 From 53a1b5b5cc47a5ee8d3865e867f0228105cd72e1 Mon Sep 17 00:00:00 2001 From: acdenisSK Date: Sun, 29 Oct 2017 21:39:14 +0100 Subject: Release v0.4.2 --- CHANGELOG.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d934490..562b973 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,56 @@ All notable changes to this project will be documented in this file. This project mostly adheres to [Semantic Versioning][semver]. +## [0.4.2] - 2017-10-29 + +This release contains the regular bugfixes, new features and slight behaviour changes. + + +Thanks to the following people for their contributions: + +- [@zeyla] +- [@acdenisSK] +- [@efyang] +- [@Caemor] +- [@Flat] +- [@hsiW] +- [@Lakelezz] +- [@UninterestinAcc] + +### Added + +- [general] Add a way to change a role's position ([@Flat]) [c:f47a0c8] +- [general] Add logging and dotenv to example 07 ([@zeyla]) [c:d50b129] +- [general] Add owner + quit function to example 07 ([@zeyla]) [c:41f26b3] +- [framework] Add `PartialEq` impls and doc-tests to `Args` ([@acdenisSK]) [c:f9e5e76] +- [framework] Add "zero-copy" parsing to `Args` ([@acdenisSK]) [c:9428787] +- [framework] Add a debug impl to `DispatchError` ([@acdenisSK]) [c:a58de97] + +### Fixed + +- [general] Fix clippy warnings ([@hsiW]) [c:fbd6258] +- [model] Fall back to `str::parse` if `utils::parse_username` fails ([@acdenisSK]) [c:292ceda] +- [model] Fix `User::has_role` ([@zeyla]) [c:d3015a0ff] +- [gateway] Fix shard connection ([@zeyla]) [c:585ac6e] +- [gateway] Fix shard shutdown via `Context` ([@zeyla]) [c:3616585] +- [framework] Fix `allow_whitespace` ([@UninterestinAcc]) [c:e694766] +- [framework, gateway, cache] Properly update emojis in the cache, fix shard re-tries and do some cleanup to `help_commands.rs` ([@Lakelezz]) [c:e02d5fb] + +### Changed + +- [model] Do equality and hashing on just the user's id ([@acdenisSK]) [c:b7cdf15] +- [model] defer to `delete_message` if there's just one message to delete ([@acdenisSK]) [c:c7aa27d] +- [model] Use the underlaying integer value of `ChannelType` ([@acdenisSK]) [c:e57b510] + +### Misc. + +- [general] Update dependencies ([@zeyla]) [c:2219bb3] +- [general] Re-export parking_lot's `Mutex` and `RwLock` from the prelude ([@zeyla]) [c:74ec713] +- [general] Update the version in `Cargo.toml` to actually be `v0.4.2` ([@Caemor]) [c:5829c67] +- [general] Cleanup gitignore to have comments ([@hsiW]) [c:ce4f8c2] +- [gateway] Use update syntax for `Shard` ([@efyang]) [c:fcc4e2c] +- [model] Deprecate some methods on `Channel` ([@zeyla]) [c:23ff6f] + ## [0.4.1] - 2017-10-14 This release contains bugfixes and some newly added or newly exposed @@ -1450,9 +1500,11 @@ Initial commit. [@barzamin]: https://github.com/barzamin [@bippum]: https://github.com/bippum [@blaenk]: https://github.com/blaenk +[@Caemor]: https://github.com/Caemor [@DeltaEvo]: https://github.com/DeltaEvo [@eLunate]: https://github.com/eLunate [@emoticon]: https://github.com/emoticon +[@efyang]: https://github.com/efyang [@Flat]: https://github.com/Flat [@foxbot]: https://github.com/foxbot [@ftriquet]: https://github.com/ftriquet @@ -1469,6 +1521,7 @@ Initial commit. [@Roughsketch]: https://github.com/Roughsketch [@sschroe]: https://github.com/sschroe [@SunDwarf]: https://github.com/SunDwarf +[@UninterestinAcc]: https://github.com/UninterestinAcc [@xentec]: https://github.com/xentec [@zeyla]: https://github.com/zeyla @@ -1848,3 +1901,26 @@ Initial commit. [c:fb07751]: https://github.com/zeyla/serenity/commit/fb07751cfc1efb657cba7005c38ed5ec6b192b4f [c:fb4d411]: https://github.com/zeyla/serenity/commit/fb4d411054fa44928b4fa052b19de19fce69d7cf [c:ff4437a]: https://github.com/zeyla/serenity/commit/ff4437addb01e5c6c3ad8c5b1830db0d0a86396b + +[c:f47a0c8]: https://github.com/zeyla/serenity/commit/f47a0c831efe5842ca38cb1067de361ae42f6edc +[c:d50b129]: https://github.com/zeyla/serenity/commit/d50b12931404946e219d3ff0878f0632445ef35f +[c:41f26b3]: https://github.com/zeyla/serenity/commit/41f26b3757c7a5fba1f09f34e3192e2fd9702a4a +[c:f9e5e76]: https://github.com/zeyla/serenity/commit/f9e5e76585a1f6317dadb67e440765b0070ca131 +[c:9428787]: https://github.com/zeyla/serenity/commit/9428787abb6126ba05bfef96cd2b8d2a217fdf5d +[c:a58de97]: https://github.com/zeyla/serenity/commit/a58de97e6089aa98f04d2cdc7312ed38a9f72b22 +[c:fbd6258]: https://github.com/zeyla/serenity/commit/fbd625839e6a2e01b16e6c3814cb9b9f31dc7caa +[c:292ceda]: https://github.com/zeyla/serenity/commit/292cedaa3462f7532efda98722354afa8e213b6a +[c:d3015a0ff]: https://github.com/zeyla/serenity/commit/d3015a0ff0c0c87888437f991945453b92296875 +[c:585ac6e]: https://github.com/zeyla/serenity/commit/585ac6e6ca792facf29063776c83262fa849161b +[c:3616585]: https://github.com/zeyla/serenity/commit/361658510f3e2eb9aefbe66232b9b1f1a1ebb80f +[c:e694766]: https://github.com/zeyla/serenity/commit/e694766bb6c93d5f6a75ad9871cfdefbd0309a17 +[c:e02d5fb]: https://github.com/zeyla/serenity/commit/e02d5fb8171b11214e1502c6754fef1972bbf1b9 +[c:b7cdf15]: https://github.com/zeyla/serenity/commit/b7cdf1542cb9199c61c0b17bdd381d4f117f635e +[c:c7aa27d]: https://github.com/zeyla/serenity/commit/c7aa27dbb64e64d70c7f13725c79017c4bba1c95 +[c:2219bb3]: https://github.com/zeyla/serenity/commit/2219bb37a80c4c2b4ff5a24d72b82737eb241195 +[c:74ec713]: https://github.com/zeyla/serenity/commit/74ec713825b2b4c55382fb76fa57bd967e66b3aa +[c:5829c67]: https://github.com/zeyla/serenity/commit/5829c673c13655b86d317ab65d204067a2b1a7a4 +[c:ce4f8c2]: https://github.com/zeyla/serenity/commit/ce4f8c2ac8dd2c472ab537a60bf92579d078073b +[c:fcc4e2c]: https://github.com/zeyla/serenity/commit/fcc4e2ce2e523248ed33c9f4853d3485cbc9b6e6 +[c:23ff6f]: https://github.com/zeyla/serenity/commit/23ff6f21019bc94f8dc32355fa34691b881bfb69 +[c:e57b510]: https://github.com/zeyla/serenity/commit/e57b510edd640abb243664337a1c163924313612 -- cgit v1.2.3 From c99091d241f240c6b76ac969655a8ec4423aaf80 Mon Sep 17 00:00:00 2001 From: acdenisSK Date: Mon, 30 Oct 2017 12:05:31 +0100 Subject: Add some docs to `BanOptions` --- src/model/guild/member.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 83cb863..6e04b98 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -16,6 +16,7 @@ use builder::EditMember; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use utils::Colour; +/// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`. pub trait BanOptions { fn dmd(&self) -> u8 { 0 } fn reason(&self) -> &str { "" } -- cgit v1.2.3 From 2ba4d03f15d57d9f0fb1cc4d4f4355ebbc483d0a Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:12:22 -0700 Subject: Add Guild::member_permissions Add a method on the Guild for calculating only a member's guild-only permissions, not including the permissions for either the default channel or any specific channel. --- src/model/guild/mod.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index aa9fd1d..0a8fe16 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -1004,6 +1004,57 @@ impl Guild { } } + /// Calculate a [`Member`]'s permissions in the guild. + /// + /// [`Member`]: struct.Member.html + pub fn member_permissions(&self, user_id: U) -> Permissions + where U: Into { + let user_id = user_id.into(); + + if user_id == self.owner_id { + return Permissions::all(); + } + + let everyone = match self.roles.get(&RoleId(self.id.0)) { + Some(everyone) => everyone, + None => { + error!( + "(╯°□°)╯︵ ┻━┻ @everyone role ({}) missing in '{}'", + self.id, + self.name, + ); + + return Permissions::empty(); + }, + }; + + let member = match self.members.get(&user_id) { + Some(member) => member, + None => return everyone.permissions, + }; + + let mut permissions = everyone.permissions; + + for role in &member.roles { + if let Some(role) = self.roles.get(&role) { + if role.permissions.contains(Permissions::ADMINISTRATOR) { + return Permissions::all(); + } + + permissions |= role.permissions; + } else { + warn!( + "(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}", + member.user.read().unwrap().id, + self.id, + role, + ); + } + } + + permissions + } + /// Moves a member to a specific voice channel. /// /// Requires the [Move Members] permission. -- cgit v1.2.3 From 1b7101fe71335c0e18bf855c0703acc23d87e427 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:14:16 -0700 Subject: Guild::has_perms: use Guild::member_permissions Make `Guild`'s internal method `has_perms` go through `Guild::member_permissions` to check permissions, since all method that use it don't need channel-specific permissions. --- src/model/guild/mod.rs | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 0a8fe16..1ad2b36 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -158,21 +158,13 @@ impl Guild { } #[cfg(feature = "cache")] - fn has_perms(&self, mut permissions: Permissions) -> Result { - let member = match self.members.get(&CACHE.read().unwrap().user.id) { - Some(member) => member, - None => return Err(Error::Model(ModelError::ItemMissing)), - }; - - let default_channel = match self.default_channel() { - Some(dc) => dc, - None => return Err(Error::Model(ModelError::ItemMissing)), - }; + fn has_perms(&self, mut permissions: Permissions) -> bool { + let user_id = CACHE.read().unwrap().user.id; - let perms = self.permissions_for(default_channel.id, member.user.read().unwrap().id); + let perms = self.member_permissions(user_id); permissions.remove(perms); - Ok(permissions.is_empty()) + permissions.is_empty() } /// Ban a [`User`] from the guild. All messages by the @@ -210,7 +202,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -235,7 +227,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -317,7 +309,7 @@ impl Guild { { let req = Permissions::MANAGE_CHANNELS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -388,7 +380,7 @@ impl Guild { { let req = Permissions::MANAGE_ROLES; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -490,7 +482,7 @@ impl Guild { { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -570,7 +562,7 @@ impl Guild { { let req = Permissions::CHANGE_NICKNAME; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -652,7 +644,7 @@ impl Guild { { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1217,7 +1209,7 @@ impl Guild { { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1300,7 +1292,7 @@ impl Guild { { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1325,7 +1317,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } -- cgit v1.2.3 From dcac27168915b4f22745950ec0ef0c0af696774e Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:17:15 -0700 Subject: Rename `Guild::permissions_for`->`permissions_in` Rename `Guild::permissions_for` to `Guild::permissions_in`, deprecating `Guild::permissions_for` which is only an inline method to `permissions_in`. --- src/framework/standard/mod.rs | 2 +- src/model/channel/guild_channel.rs | 2 +- src/model/guild/member.rs | 4 ++-- src/model/guild/mod.rs | 17 ++++++++++++++--- src/model/utils.rs | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index f4c98e8..9ad68da 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -972,7 +972,7 @@ pub fn has_correct_permissions(command: &Command, message: &Message) -> bool { if !command.required_permissions.is_empty() { if let Some(guild) = message.guild() { let perms = guild - .with(|g| g.permissions_for(message.channel_id, message.author.id)); + .with(|g| g.permissions_in(message.channel_id, message.author.id)); return perms.contains(command.required_permissions); } diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index d6649b4..b7295fc 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -512,7 +512,7 @@ impl GuildChannel { pub fn permissions_for>(&self, user_id: U) -> Result { self.guild() .ok_or_else(|| Error::Model(ModelError::GuildNotFound)) - .map(|g| g.read().unwrap().permissions_for(self.id, user_id)) + .map(|g| g.read().unwrap().permissions_in(self.id, user_id)) } /// Pins a [`Message`] to the channel. diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 6e04b98..a9de969 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -257,7 +257,7 @@ impl Member { .get(&self.guild_id) .map(|guild| guild.read().unwrap().has_perms(req)); - if let Some(Ok(false)) = has_perms { + if let Some(false) = has_perms { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -301,7 +301,7 @@ impl Member { Ok( guild - .permissions_for(default_channel.id, self.user.read().unwrap().id), + .permissions_in(default_channel.id, self.user.read().unwrap().id), ) } diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 1ad2b36..fe9bc6a 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -132,7 +132,7 @@ impl Guild { let uid = CACHE.read().unwrap().user.id; for (cid, channel) in &self.channels { - if self.permissions_for(*cid, uid).read_messages() { + if self.permissions_in(*cid, uid).read_messages() { return Some(channel.read().unwrap().clone()); } } @@ -148,7 +148,7 @@ impl Guild { pub fn default_channel_guaranteed(&self) -> Option { for (cid, channel) in &self.channels { for memid in self.members.keys() { - if self.permissions_for(*cid, *memid).read_messages() { + if self.permissions_in(*cid, *memid).read_messages() { return Some(channel.read().unwrap().clone()); } } @@ -1058,10 +1058,21 @@ impl Guild { self.id.move_member(user_id, channel_id) } + /// Alias for [`permissions_in`]. + /// + /// [`permissions_in`]: #method.permissions_in + #[deprecated(since = "0.4.3", + note = "This will serve a different purpose in 0.5")] + #[inline] + pub fn permissions_for(&self, channel_id: C, user_id: U) + -> Permissions where C: Into, U: Into { + self.permissions_in(channel_id, user_id) + } + /// Calculate a [`User`]'s permissions in a given channel in the guild. /// /// [`User`]: struct.User.html - pub fn permissions_for(&self, channel_id: C, user_id: U) -> Permissions + pub fn permissions_in(&self, channel_id: C, user_id: U) -> Permissions where C: Into, U: Into { let user_id = user_id.into(); diff --git a/src/model/utils.rs b/src/model/utils.rs index 719a472..a64156b 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -180,7 +180,7 @@ pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Re let perms = guild .read() .unwrap() - .permissions_for(channel_id, current_user.id); + .permissions_in(channel_id, current_user.id); permissions.remove(perms); -- cgit v1.2.3 From bb205d28ea28fd8ac005ce66c90aa6cf2ca85e45 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:17:34 -0700 Subject: Fix extraneous whitespace --- src/framework/standard/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index 9ad68da..a806817 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -143,7 +143,7 @@ use std::fmt; impl fmt::Debug for DispatchError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::DispatchError::*; - + match *self { CheckFailed(..) => write!(f, "DispatchError::CheckFailed"), CommandDisabled(ref s) => f.debug_tuple("DispatchError::CommandDisabled").field(&s).finish(), -- cgit v1.2.3 From 3be6e2e28b0c3e9baaef19f405c463e3a41fed25 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 21:07:08 -0700 Subject: Slightly clarify ratelimiting documentation --- src/http/ratelimiting.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs index dbaca6b..8008616 100644 --- a/src/http/ratelimiting.rs +++ b/src/http/ratelimiting.rs @@ -339,8 +339,8 @@ pub enum Route { VoiceRegions, /// Route for the `/webhooks/:webhook_id` path. WebhooksId, - /// Route where no ratelimit headers are in place (i.e. user account-only - /// routes). + /// Route where no ratelimit headers are in place (e.g. current application + /// info retrieval). /// /// This is a special case, in that if the route is `None` then pre- and /// post-hooks are not executed. -- cgit v1.2.3 From d3eddc68e07bbc31e2043577cbf48741f0547ed3 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Tue, 31 Oct 2017 08:51:43 -0700 Subject: Make Member::permissions return guild permissions Fixes what is realistically a bug where `Member::permissions` would retrieve the permissions for the Member in the default channel of the guild. This now only returns the guild-level permissions of the member. --- src/model/guild/member.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index a9de969..c81e2a3 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -265,7 +265,7 @@ impl Member { self.guild_id.kick(self.user.read().unwrap().id) } - /// Returns the permissions for the member. + /// Returns the guild-level permissions for the member. /// /// # Examples /// @@ -292,17 +292,9 @@ impl Member { None => return Err(From::from(ModelError::GuildNotFound)), }; - let guild = guild.read().unwrap(); + let reader = guild.read().unwrap(); - let default_channel = match guild.default_channel() { - Some(dc) => dc, - None => return Err(From::from(ModelError::ItemMissing)), - }; - - Ok( - guild - .permissions_in(default_channel.id, self.user.read().unwrap().id), - ) + Ok(reader.member_permissions(self.user.read().unwrap().id)) } /// Removes a [`Role`] from the member, editing its roles in-place if the -- cgit v1.2.3 From 800e58f4603ce99ab69569b30cbec756301a6a63 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 31 Oct 2017 16:27:53 -0600 Subject: Fix ping bot example (#211) --- README.md | 7 ++++++- src/lib.rs | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c687581..a75872d 100644 --- a/README.md +++ b/README.md @@ -42,12 +42,17 @@ A basic ping-pong bot looks like: #[macro_use] extern crate serenity; use serenity::client::Client; +use serenity::prelude::EventHandler; use serenity::framework::standard::StandardFramework; use std::env; +struct Handler; + +impl EventHandler for Handler {} + fn main() { // Login with a bot token from the environment - let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token")); + let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token"), Handler); client.with_framework(StandardFramework::new() .configure(|c| c.prefix("~")) // set the bot's prefix to "~" .on("ping", ping)); diff --git a/src/lib.rs b/src/lib.rs index 471d41b..7e5609a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,12 +33,17 @@ //! #[macro_use] extern crate serenity; //! //! use serenity::client::Client; +//! use serenity::prelude::EventHandler; //! use serenity::framework::standard::StandardFramework; //! use std::env; //! +//! struct Handler; +//! +//! impl EventHandler for Handler {} +//! //! fn main() { //! // Login with a bot token from the environment -//! let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token")); +//! let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token"), Handler); //! client.with_framework(StandardFramework::new() //! .configure(|c| c.prefix("~")) // set the bot's prefix to "~" //! .on("ping", ping)); -- cgit v1.2.3 From e219a6a9d6a890b008fc390a909ae504a0c1a329 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 07:48:24 -0700 Subject: Use consistent token names in examples The names of environment variable tokens in the examples differed, so this makes them all use the same name. --- src/client/mod.rs | 2 +- src/framework/mod.rs | 2 +- src/framework/standard/configuration.rs | 2 +- src/gateway/shard.rs | 2 +- src/model/error.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client/mod.rs b/src/client/mod.rs index 0a3c49f..6711287 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -685,7 +685,7 @@ impl Client { /// use serenity::Client; /// use std::env; /// - /// let token = env::var("DISCORD_BOT_TOKEN").unwrap(); + /// let token = env::var("DISCORD_TOKEN").unwrap(); /// let mut client = Client::new(&token, Handler); /// /// let _ = client.start_shard_range([4, 7], 10); diff --git a/src/framework/mod.rs b/src/framework/mod.rs index a5f458d..85ae6f4 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -36,7 +36,7 @@ //! use serenity::model::Message; //! use std::env; //! -//! let mut client = Client::new(&env::var("DISCORD_BOT_TOKEN").unwrap()); +//! let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap()); //! //! client.with_framework(|f| f //! .configure(|c| c.prefix("~")) diff --git a/src/framework/standard/configuration.rs b/src/framework/standard/configuration.rs index 8cc25fa..c731d31 100644 --- a/src/framework/standard/configuration.rs +++ b/src/framework/standard/configuration.rs @@ -24,7 +24,7 @@ use model::{GuildId, Message, UserId}; /// use std::env; /// use serenity::framework::StandardFramework; /// -/// let mut client = Client::new(&env::var("DISCORD_BOT_TOKEN").unwrap(), Handler); +/// let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap(), Handler); /// /// client.with_framework(StandardFramework::new() /// .configure(|c| c.on_mention(true).prefix("~"))); diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index e5fe65d..f5888af 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -116,7 +116,7 @@ impl Shard { /// use serenity::http; /// use std::env; /// - /// let token = env::var("DISCORD_BOT_TOKEN").expect("Token in environment"); + /// let token = env::var("DISCORD_TOKEN").expect("Token in environment"); /// // retrieve the gateway response, which contains the URL to connect to /// let gateway = http::get_gateway().expect("Valid gateway response").url; /// let shard = Shard::new(&gateway, &token, None) diff --git a/src/model/error.rs b/src/model/error.rs index fa24272..57801da 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -46,7 +46,7 @@ use super::Permissions; /// } /// } /// } -/// let token = env::var("DISCORD_BOT_TOKEN")?; +/// let token = env::var("DISCORD_TOKEN")?; /// let mut client = Client::new(&token, Handler); client.start()?; /// # Ok(()) /// # } -- cgit v1.2.3 From 1d632f72824e7c4d070169ae0b450f1d3594f434 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 11:12:10 -0700 Subject: Fix no-parking_lot compilation Fixes compilation without the `parking_lot` crate compiled. The prelude re-exposed `parking_lot`'s `Mutex` and `RwLock`, but didn't do so conditionally. --- src/prelude.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/prelude.rs b/src/prelude.rs index 435fb8a..8a361e9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -16,7 +16,6 @@ pub use error::Error as SerenityError; pub use model::Mentionable; -pub use parking_lot::{Mutex, RwLock}; #[cfg(feature = "client")] pub use client::{Client, ClientError as ClientError, Context, EventHandler}; @@ -26,5 +25,7 @@ pub use gateway::GatewayError; pub use http::HttpError; #[cfg(feature = "model")] pub use model::ModelError; +#[cfg(feature = "parking_lot")] +pub use parking_lot::{Mutex, RwLock}; #[cfg(feature = "voice")] pub use voice::VoiceError; -- cgit v1.2.3 From ccbc3b348fe41aaad74c7676f1334be246008cae Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 12:45:21 -0700 Subject: Fix no-client cache tests There were a few doctests in the cache module that relied on the client module, so instead feature-gate the doctests. --- src/builder/create_embed.rs | 2 +- src/builder/create_invite.rs | 10 +++++----- src/cache/mod.rs | 44 +++++++++++++++++++++++++++++++++----------- src/model/user.rs | 12 ++++++------ 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs index cc5e642..b38984c 100644 --- a/src/builder/create_embed.rs +++ b/src/builder/create_embed.rs @@ -248,7 +248,7 @@ impl CreateEmbed { /// struct Handler; /// impl EventHandler for Handler { /// fn on_guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// let cache = CACHE.read().unwrap(); /// /// if let Some(guild) = cache.guild(guild_id) { diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs index 5f4f0bf..645d401 100644 --- a/src/builder/create_invite.rs +++ b/src/builder/create_invite.rs @@ -19,7 +19,7 @@ use internal::prelude::*; /// /// impl EventHandler for Handler { /// fn on_message(&self, _: Context, msg: Message) { -/// use serenity::client::CACHE; +/// use serenity::CACHE; /// if msg.content == "!createinvite" { /// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) { /// Some(channel) => channel, @@ -72,7 +72,7 @@ impl CreateInvite { /// Create an invite with a max age of `3600` seconds, or 1 hour: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -106,7 +106,7 @@ impl CreateInvite { /// Create an invite with a max use limit of `5`: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -138,7 +138,7 @@ impl CreateInvite { /// Create an invite which is temporary: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -170,7 +170,7 @@ impl CreateInvite { /// Create an invite which is unique: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 921e77b..357092f 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -169,7 +169,9 @@ impl Cache { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// # #[cfg(feature = "client")] + /// # fn main() { + /// use serenity::CACHE; /// use std::thread; /// use std::time::Duration; /// @@ -193,6 +195,10 @@ impl Cache { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`Member`]: ../model/struct.Member.html @@ -225,7 +231,7 @@ impl Cache { /// Printing the count of all private channels and groups: /// /// ```rust,no_run - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let amount = CACHE.read().unwrap().all_private_channels().len(); /// @@ -252,10 +258,12 @@ impl Cache { /// Print all of the Ids of guilds in the Cache: /// /// ```rust,no_run + /// # #[cfg(feature = "client")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// struct Handler; /// impl EventHandler for Handler { @@ -264,6 +272,10 @@ impl Cache { /// } /// } /// let mut client = Client::new("token", Handler); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`Context`]: ../client/struct.Context.html @@ -330,7 +342,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -361,10 +373,12 @@ impl Cache { /// [`Client::on_message`] event dispatch: /// /// ```rust,no_run + /// # #[cfg(feature = "client")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// struct Handler; /// @@ -387,6 +401,10 @@ impl Cache { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`ChannelId`]: ../model/struct.ChannelId.html @@ -415,7 +433,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -494,18 +512,22 @@ impl Cache { /// /// # Examples /// - /// Retrieve a private channel from the cache and send a message: + /// Retrieve a private channel from the cache and print its recipient's + /// name: /// /// ```rust,no_run /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// /// if let Some(channel) = cache.private_channel(7) { - /// channel.read().unwrap().say("Hello there!"); + /// let channel_reader = channel.read().unwrap(); + /// let user_reader = channel_reader.recipient.read().unwrap(); + /// + /// println!("The recipient is {}", user_reader.name); /// } /// # Ok(()) /// # } @@ -537,7 +559,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -574,7 +596,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// diff --git a/src/model/user.rs b/src/model/user.rs index 3d39759..bf725cc 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -44,7 +44,7 @@ impl CurrentUser { /// Print out the current user's avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -121,7 +121,7 @@ impl CurrentUser { /// Print out the names of all guilds the current user is in: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -149,7 +149,7 @@ impl CurrentUser { /// Get the invite url with no permissions set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let mut cache = CACHE.write().unwrap(); /// @@ -172,7 +172,7 @@ impl CurrentUser { /// Get the invite url with some basic permissions set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let mut cache = CACHE.write().unwrap(); /// @@ -228,7 +228,7 @@ impl CurrentUser { /// Print out the current user's static avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -252,7 +252,7 @@ impl CurrentUser { /// Print out the current user's distinct identifier (e.g., Username#1234): /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # -- cgit v1.2.3 From 2c59f87c1408ef633b8749f6688dc42129054a36 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 13:10:16 -0700 Subject: Fix doctests for a variety of feature targets --- src/cache/mod.rs | 6 ++++-- src/client/context.rs | 6 ++++++ src/gateway/shard.rs | 21 +++++++++++++++++++-- src/model/error.rs | 8 ++++---- tests/test_channels.rs | 2 ++ tests/test_create_embed.rs | 2 +- 6 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 357092f..a663a79 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -266,12 +266,14 @@ impl Cache { /// use serenity::CACHE; /// /// struct Handler; + /// /// impl EventHandler for Handler { /// fn on_ready(&self, _: Context, _: Ready) { - /// println!("Guilds in the Cache: {:?}", CACHE.read().unwrap().all_guilds()); + /// let guilds = CACHE.read().unwrap().guilds.len(); + /// + /// println!("Guilds in the Cache: {}", guilds); /// } /// } - /// let mut client = Client::new("token", Handler); /// # } /// # /// # #[cfg(not(feature = "client"))] diff --git a/src/client/context.rs b/src/client/context.rs index 2288f28..d0a6fc7 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -263,6 +263,8 @@ impl Context { /// playing: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # @@ -282,6 +284,10 @@ impl Context { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` /// /// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index f5888af..bd60b57 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -235,6 +235,8 @@ impl Shard { /// Setting the current game to playing `"Heroes of the Storm"`: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::client::gateway::Shard; /// # use std::sync::{Arc, Mutex}; /// # @@ -245,6 +247,10 @@ impl Shard { /// use serenity::model::Game; /// /// shard.set_game(Some(Game::playing("Heroes of the Storm"))); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` pub fn set_game(&mut self, game: Option) { self.current_presence.0 = game; @@ -299,6 +305,8 @@ impl Shard { /// and not being afk: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::client::gateway::Shard; /// # use std::sync::{Arc, Mutex}; /// # @@ -308,8 +316,11 @@ impl Shard { /// # /// use serenity::model::{Game, OnlineStatus}; /// - /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online, - /// false); + /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online, false); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` pub fn set_presence(&mut self, game: Option, mut status: OnlineStatus, afk: bool) { if status == OnlineStatus::Offline { @@ -569,6 +580,8 @@ impl Shard { /// message handled through [`Client::on_message`]. /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// struct Handler; @@ -587,6 +600,10 @@ impl Shard { /// } /// } /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` /// /// [`Client`]: ../struct.Client.html diff --git a/src/model/error.rs b/src/model/error.rs index 57801da..454b94b 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -13,10 +13,10 @@ use super::Permissions; /// re-ban all members with an odd discriminator: /// /// ```rust,no_run -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # use std::error::Error; /// # -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # fn try_main() -> Result<(), Box> { /// use serenity::prelude::*; /// use serenity::model::*; @@ -51,12 +51,12 @@ use super::Permissions; /// # Ok(()) /// # } /// # -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # fn main() { /// # try_main().unwrap(); /// # } /// # -/// # #[cfg(not(feature="client"))] +/// # #[cfg(not(all(feature="client", feature = "model")))] /// # fn main() { } /// ``` /// diff --git a/tests/test_channels.rs b/tests/test_channels.rs index 7a3f9c3..d871d5d 100644 --- a/tests/test_channels.rs +++ b/tests/test_channels.rs @@ -1,3 +1,5 @@ +#![cfg(feature = "model")] + extern crate serenity; #[cfg(feature = "utils")] diff --git a/tests/test_create_embed.rs b/tests/test_create_embed.rs index 8cc0de7..5c51dc6 100644 --- a/tests/test_create_embed.rs +++ b/tests/test_create_embed.rs @@ -1,5 +1,5 @@ #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] -#![cfg(feature = "utils")] +#![cfg(all(feature = "builder", feature = "utils"))] #[macro_use] extern crate serde_json; -- cgit v1.2.3 From f218fd4b3f78fa250f9cee7dea2119cae8a7747f Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 13:36:55 -0700 Subject: Bump to v0.4.3 --- CHANGELOG.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- Cargo.toml | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 562b973..2a6fdd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,47 @@ All notable changes to this project will be documented in this file. This project mostly adheres to [Semantic Versioning][semver]. -## [0.4.2] - 2017-10-29 +## [0.4.3] - 2017-11-01 + +This release contains bugfixes and marks the final release of the v0.4.x branch. +Future development will continue on the v0.5.x branch. + +Thanks to the following for their contributions: + +- [@acdenisSK] +- [@ThatsNoMoon] +- [@zeyla] + +### Added + +- [model] Add `Guild::member_permissions` ([@zeyla]) [c:2ba4d03] + +### Changed -This release contains the regular bugfixes, new features and slight behaviour changes. +- [model] Rename `Guild::permissions_for` to `Guild::permissions_in`, keep an + alias ([@zeyla]) [c:dcac271] +### Fixed + +- [model] Make `Member::permissions` return guild-level permissions ([@zeyla]) + [c:d3eddc6] + +### Misc. + +- [model] Add some docs to `BanOptions` ([@acdenisSK]) [c:c99091d] +- [model] Have `Guild::has_perms` use `Guild::member_permissions` ([@zeyla]) + [c:1b7101f] +- [http] Slightly clarify ratelimiting documentation ([@zeyla]) [c:3be6e2e] +- [docs] Fix ping bot example ([@ThatsNoMoon]) [c:800e58f] +- [docs] Use consistent token names in examples ([@zeyla]) [c:e219a6a] + +## [0.4.2] - 2017-10-29 + +This release contains the regular bugfixes, new features and slight behaviour +changes. Thanks to the following people for their contributions: -- [@zeyla] - [@acdenisSK] - [@efyang] - [@Caemor] @@ -18,6 +51,7 @@ Thanks to the following people for their contributions: - [@hsiW] - [@Lakelezz] - [@UninterestinAcc] +- [@zeyla] ### Added @@ -1477,6 +1511,8 @@ rest::get_guilds(GuildPagination::After(GuildId(777)), 50); Initial commit. +[0.4.3]: https://github.com/zeyla/serenity/compare/v0.4.2...v0.4.3 +[0.4.2]: https://github.com/zeyla/serenity/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/zeyla/serenity/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/zeyla/serenity/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/zeyla/serenity/compare/v0.2.0...v0.3.0 @@ -1521,10 +1557,20 @@ Initial commit. [@Roughsketch]: https://github.com/Roughsketch [@sschroe]: https://github.com/sschroe [@SunDwarf]: https://github.com/SunDwarf +[@ThatsNoMoon]: https://github.com/ThatsNoMoon [@UninterestinAcc]: https://github.com/UninterestinAcc [@xentec]: https://github.com/xentec [@zeyla]: https://github.com/zeyla +[c:1b7101f]: https://github.com/zeyla/serenity/commit/1b7101fe71335c0e18bf855c0703acc23d87e427 +[c:2ba4d03]: https://github.com/zeyla/serenity/commit/2ba4d03f15d57d9f0fb1cc4d4f4355ebbc483d0a +[c:3be6e2e]: https://github.com/zeyla/serenity/commit/3be6e2e28b0c3e9baaef19f405c463e3a41fed25 +[c:800e58f]: https://github.com/zeyla/serenity/commit/800e58f4603ce99ab69569b30cbec756301a6a63 +[c:c99091d]: https://github.com/zeyla/serenity/commit/c99091d241f240c6b76ac969655a8ec4423aaf80 +[c:d3eddc6]: https://github.com/zeyla/serenity/commit/d3eddc68e07bbc31e2043577cbf48741f0547ed3 +[c:dcac271]: https://github.com/zeyla/serenity/commit/dcac27168915b4f22745950ec0ef0c0af696774e +[c:e219a6a]: https://github.com/zeyla/serenity/commit/e219a6a9d6a890b008fc390a909ae504a0c1a329 + [c:002ce3a]: https://github.com/zeyla/serenity/commit/002ce3aa272fa51b84e820f12db39cb87a461a83 [c:022e35d]: https://github.com/zeyla/serenity/commit/022e35d5b12322bd77bbe74a1a3b2ad319977390 [c:05f158f]: https://github.com/zeyla/serenity/commit/05f158fc89f2adc82e31cf4b93706dc7d25e11d8 diff --git a/Cargo.toml b/Cargo.toml index a287ea3..2094590 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "ISC" name = "serenity" readme = "README.md" repository = "https://github.com/zeyla/serenity.git" -version = "0.4.2" +version = "0.4.3" [dependencies] bitflags = "^1.0" -- cgit v1.2.3