Skip to content
This repository has been archived by the owner on Jan 4, 2022. It is now read-only.

Commit

Permalink
implement basic userinfo (closes #4)
Browse files Browse the repository at this point in the history
parse users as command param (id and mention only, #1)
split up context for better manangement
  • Loading branch information
AEnterprise authored and BlackHoleFox committed May 4, 2020
1 parent b6941fc commit 9575ce0
Show file tree
Hide file tree
Showing 21 changed files with 939 additions and 33 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ chrono = "0.4"
deadpool-postgres={version = "0.5", features=["config"]}
dashmap = "3.11"
flexi_logger = { version = "0.15", default_features = false, features = ["colors", "specfile", "ziplogs"] }
futures = "0.3"
git-version = "0.3"
lazy_static = "1.4"
log = "0.4"
Expand All @@ -28,6 +29,7 @@ toml = "0.5"
twilight = { git = "https://github.com/AEnterprise/twilight/", branch="gearbot" }
tokio-postgres = { version = "0.5", default_features = false }
url = "2.1"
uuid = { version = "0.8", features = ["serde", "v4"] }

[profile.dev]
debug = 0
Expand Down
File renamed without changes.
4 changes: 3 additions & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::commands::meta::nodes::CommandNode;
use crate::{command, subcommands};
pub mod basic;
pub mod meta;
pub mod moderation;

static ROOT_NODE: OnceCell<CommandNode> = OnceCell::new();

Expand All @@ -18,7 +19,8 @@ pub fn get_root() -> &'static CommandNode {
command!("coinflip", basic::coinflip),
command!("ping", basic::ping),
command!("echo", basic::echo),
command!("about", basic::about)
command!("about", basic::about),
command!("userinfo", moderation::userinfo)
))
.ok()
.unwrap();
Expand Down
3 changes: 3 additions & 0 deletions src/commands/moderation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod userinfo;

pub use userinfo::userinfo;
195 changes: 195 additions & 0 deletions src/commands/moderation/userinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
use crate::core::Context;
use crate::parser::Parser;
use crate::utils::Emoji;
use crate::utils::{CommandError, Error};
use crate::{utils, CommandResult};
use chrono::{DateTime, Utc};
use log::debug;
use serde::export::TryFrom;
use std::borrow::Borrow;
use std::sync::Arc;
use std::time::Duration;
use twilight::builders::embed::EmbedBuilder;
use twilight::model::channel::Message;
use twilight::model::id::ChannelId;
use twilight::model::user::UserFlags;

pub async fn userinfo(ctx: Arc<Context>, msg: Message, mut parser: Parser) -> CommandResult {
if msg.guild_id.is_none() {
return Err(Error::CmdError(CommandError::NoDM));
}

let user = parser.get_user().await?;

//set some things that are the same regardless
let mut content = "".to_string();

let mut builder = EmbedBuilder::new();
let mut author_builder = builder
.author()
.name(format!("{}#{}", user.name, user.discriminator));
if user.avatar.is_some() {
let avatar = user.avatar.as_ref().unwrap();
let extension = if avatar.starts_with("a_") {
"gif"
} else {
"png"
};
author_builder = author_builder.icon_url(format!(
"https://cdn.discordapp.com/avatars/{}/{}.{}",
user.id,
user.avatar.as_ref().unwrap(),
extension
))
}
builder = author_builder.commit();

//add badges
let flags = match user.public_flags {
Some(flags) => flags,
None => {
// we already know for sure the user will exist
let user = ctx.http.user(user.id.0).await?.unwrap();
//TODO insert in cache when possible
user.public_flags.unwrap()
}
};

if flags.contains(UserFlags::DISCORD_EMPLOYEE) {
content += Emoji::StaffBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::DISCORD_PARTNER) {
content += Emoji::PartnerBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::HYPESQUAD_EVENTS) {
content += Emoji::HypesquadEvents.for_chat();
content += " ";
}

if flags.contains(UserFlags::BUG_HUNTER) {
content += Emoji::BugHunterBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::HOUSE_BRAVERY) {
content += Emoji::BraveryBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::HOUSE_BRILLIANCE) {
content += Emoji::BrillianceBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::HOUSE_BALANCE) {
content += Emoji::BalanceBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::BUG_HUNTER_LEVEL_2) {
content += Emoji::BugHunterLvl2Badge.for_chat();
content += " ";
}

if flags.contains(UserFlags::VERIFIED_BOT_DEVELOPER) {
content += Emoji::VerifiedBotDevBadge.for_chat();
content += " ";
}

if flags.contains(UserFlags::EARLY_SUPPORTER) {
content += Emoji::EarlySupporterBadge.for_chat();
}

content += if user.bot {
Emoji::Robot.for_chat()
} else {
""
};

let created_at = utils::snowflake_timestamp(user.id.0);

content += &format!(
"\n**User id**: {}\n**Account created on**: {}\n**Account Age**: {}\n\n",
user.id,
created_at.format("%A %d %B %Y (%T)"),
utils::age(created_at, Utc::now(), 2)
);

match ctx
.cache
.member(msg.guild_id.unwrap(), user.id)
.await
.unwrap()
{
Some(member) => {
if member.roles.first().is_some() {
let role = member.roles.first().unwrap().clone();
let cached_role = ctx.cache.role(role).await?.unwrap();
builder = builder.color(cached_role.color);
let (joined, ago) = match &member.joined_at {
Some(joined) => {
let joined = DateTime::from_utc(
DateTime::parse_from_str(joined, "%FT%T%.f%z")
.unwrap()
.naive_utc(),
Utc,
);
(
joined.format("%A %d %B %Y (%T)").to_string(),
utils::age(joined, Utc::now(), 2),
)
}
None => ("Unknown".to_string(), "Unknown".to_string()),
};

let mut count = 0;
let mut roles = "".to_string();
for role in &member.roles {
if count > 0 {
roles += ", ";
}
roles += &format!("<@&{}>", role.0);
count += 1;
if count == 3 {
roles += &format!(" and {} more", member.roles.len() - 3);
break;
}
}

content += &format!(
"**Joined on**: {}\n**Been here for**: {}\n**Roles**:{}",
joined, ago, roles
);
match &member.premium_since {
Some(s) => {
let since: DateTime<Utc> = DateTime::from_utc(
DateTime::parse_from_str(&*s, "%FT%T%.f%z")
.unwrap()
.naive_utc(),
Utc,
);
content += &format!("**Boosting this server since**: {}", since);
}
None => {}
}
}
}
None => {
builder = builder.color(0x00cea2);
}
}

builder = builder.description(content);

ctx.http
.create_message(msg.channel_id)
.content(format!("User information about <@!{}>", user.id))
.embed(builder.build())
.await?;

Ok(())
}
45 changes: 45 additions & 0 deletions src/core/context/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::core::Context;
use crate::utils::ParseError::MemberNotFoundById;
use crate::utils::{Error, ParseError};
use futures::channel::oneshot;
use log::debug;
use std::sync::Arc;
use twilight::http::error::Error::Response;
use twilight::http::error::ResponseError::{Client, Server};
use twilight::http::error::{Error as HttpError, ResponseError};
use twilight::model::gateway::payload::{MemberChunk, RequestGuildMembers};
use twilight::model::gateway::presence::Presence;
use twilight::model::guild::Member;
use twilight::model::id::UserId;
use twilight::model::user::User;
use uuid::Uuid;

impl Context {
pub async fn get_user(&self, user_id: UserId) -> Result<Arc<User>, Error> {
match self.cache.user(user_id).await? {
Some(user) => Ok(user),
None => {
// let's see if we can get em from the api
let result = self.http.user(user_id.0).await;
//TODO: cache in redis

match result {
Ok(u) => {
let user = u.unwrap(); // there isn't a codepath that can even give none for this atm
Ok(Arc::new(user))
}
Err(error) => {
//2 options here:
//1) drill down 3 layers and get a headache trying to deal with moving and re-assembling errors to figure out the status code
//2) just get the string and find the code in there
if format!("{:?}", error).contains("status: 404") {
Err(Error::ParseError(ParseError::InvalidUserID(user_id.0)))
} else {
Err(Error::TwilightHttp(error))
}
}
}
}
}
}
}
Loading

0 comments on commit 9575ce0

Please sign in to comment.