Compare commits
10 commits
bf25393ad3
...
433f99929d
Author | SHA1 | Date | |
---|---|---|---|
433f99929d | |||
f3811ac712 | |||
bbe1ee264b | |||
60ac0142e9 | |||
59d752c44c | |||
ab6c2af41e | |||
18cba1fb39 | |||
|
aab98e3e7e | ||
|
7e9d15b05e | ||
d1278ce4e0 |
9 changed files with 966 additions and 668 deletions
14
.github/workflows/cargo-audit.yml
vendored
Normal file
14
.github/workflows/cargo-audit.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: Security audit
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- '**/Cargo.toml'
|
||||||
|
- '**/Cargo.lock'
|
||||||
|
jobs:
|
||||||
|
security_audit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: rustsec/audit-check@v1.4.1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
1471
Cargo.lock
generated
1471
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
38
Cargo.toml
38
Cargo.toml
|
@ -24,36 +24,36 @@ poise = { version = "0.5.6", features = [
|
||||||
"cache",
|
"cache",
|
||||||
"collector",
|
"collector",
|
||||||
] }
|
] }
|
||||||
tokio = { version = "1.32.0", features = ["full"] }
|
tokio = { version = "1.38.0", features = ["full"] }
|
||||||
csv = "1.2.2"
|
csv = "1.3.0"
|
||||||
serde = "1.0.188"
|
serde = "1.0.203"
|
||||||
serde_json = "1.0.107"
|
serde_json = "1.0.120"
|
||||||
uwuify = "0.2.2"
|
uwuify = "0.2.2"
|
||||||
chrono = "0.4.31"
|
chrono = "0.4.38"
|
||||||
clap = { version = "4.0.32", features = ["derive"] }
|
clap = { version = "4.5.8", features = ["derive"] }
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
colored = "2.0.4"
|
colored = "2.1.0"
|
||||||
strip_markdown = "0.2.0"
|
strip_markdown = "0.2.0"
|
||||||
reqwest = "0.11.20"
|
reqwest = { version = "0.12.5", features = ["json"] }
|
||||||
futures = "0.3.28"
|
futures = "0.3.30"
|
||||||
redis = { version = "0.23.3", features = ["aio", "tokio-comp"] }
|
redis = { version = "0.25.4", features = ["aio", "tokio-comp"] }
|
||||||
merge = { version = "0.1.0", features = ["std", "num", "derive"] }
|
merge = { version = "0.1.0", features = ["std", "num", "derive"] }
|
||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
unix-time = "0.1.5"
|
unix-time = "0.1.5"
|
||||||
regex = "1.9.5"
|
regex = "1.10.5"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.19.0"
|
||||||
chrono-tz = "0.8.3"
|
chrono-tz = "0.9.0"
|
||||||
meilisearch-sdk = "0.17.0"
|
meilisearch-sdk = "0.26.1"
|
||||||
serde_with = "3.3.0"
|
serde_with = "3.8.2"
|
||||||
tracing = { version = "0.1.37", features = ["async-await"] }
|
tracing = { version = "0.1.40", features = ["async-await"] }
|
||||||
tracing-subscriber = { version = "0.3.17", features = [
|
tracing-subscriber = { version = "0.3.18", features = [
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"registry",
|
"registry",
|
||||||
] }
|
] }
|
||||||
linkify = "0.10.0"
|
linkify = "0.10.0"
|
||||||
anyhow = "1.0.75"
|
anyhow = "1.0.86"
|
||||||
thiserror = "1.0.49"
|
thiserror = "1.0.61"
|
||||||
pastemyst = "1.0.0"
|
pastemyst = "1.0.0"
|
||||||
# oxipng = "5.0.1"
|
# oxipng = "5.0.1"
|
||||||
# mozjpeg = "0.9.3"
|
# mozjpeg = "0.9.3"
|
||||||
|
|
61
README.md
61
README.md
|
@ -4,39 +4,39 @@ This is the source code for the [FBTHeaven discord bot](https://fbtsecurity.fbth
|
||||||
|
|
||||||
[FBT Links](https://linktr.ee/FBT_Heaven)
|
[FBT Links](https://linktr.ee/FBT_Heaven)
|
||||||
|
|
||||||
## about
|
## About
|
||||||
|
|
||||||
I am the developer for version 2.0, it has been a stale unmaintained project for months but I didn't want my source to just wither untouched so I removed the API keys and added a hand full of `// TODO:`s to the code for you to find what discord IDs you need to change and what other keys you need to provide.
|
I am the developer for version 2.0, it has been a stale unmaintained project for months but I didn't want my source to just wither untouched -- so I removed the API keys and added a handful of `// TODO:`s to the code for you to find what discord IDs you need to change and what other keys you need to provide.
|
||||||
|
|
||||||
You will need a [Redis DB](https://redis.io/) for a bunch of features, no guide on setting one up atm (or possibly every, we'll see how I feel later)
|
You will need a [Redis DB](https://redis.io/) for a bunch of features, no guide on setting one up atm (or possibly ever, we'll see how I feel later)
|
||||||
You can also update a [Meilisearch DB](https://www.meilisearch.com/) with the same data, that one command is easy to comment out if you don't want to use that too
|
You can also update a [Meilisearch DB](https://www.meilisearch.com/) with the same data, that one command is easy to comment out if you don't want to use that too
|
||||||
|
|
||||||
## redis layout
|
## Redis layout
|
||||||
|
|
||||||
The db is split into 8 "folders".
|
The db is split into 8 "folders".
|
||||||
Redis is a key:value DB meaning you have just the name of the DB entry and then it's value, an example of this is the entry `user:0000000000000000000` which is an entry in the user "folder".
|
Redis is a key:value DB meaning you have just the name of the DB entry and then its value, an example of this is the entry `user:0000000000000000000` which is an entry in the user "folder".
|
||||||
|
|
||||||
here are the "folders" and their descriptions:
|
here are the "folders" and their descriptions:
|
||||||
|
|
||||||
- `authed-server-users:<DiscordServerID>`
|
- `authed-server-users:<DiscordServerID>`
|
||||||
- This is a Redis [SET](https://redis.io/docs/latest/develop/data-types/sets/) of discord user IDs who are authenticated in the server in the DB entry
|
- This is a Redis [SET](https://redis.io/docs/latest/develop/data-types/sets/) of discord user IDs who are authenticated in the server in the DB entry
|
||||||
- `cleared-suer:<DiscordUserID>`
|
- `cleared-suer:<DiscordUserID>`
|
||||||
- this is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry of users who are cleared as okay in the DB after being flagged
|
- This is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry of users who are cleared as okay in the DB after being flagged
|
||||||
- Json format:
|
- JSON format:
|
||||||
|
|
||||||
```JSON
|
```json
|
||||||
{
|
{
|
||||||
"user_id": "0000000000000000000",
|
"user_id": "0000000000000000000",
|
||||||
"username": "TestUsername#0001",
|
"username": "TestUsername#0001",
|
||||||
"where_found": "Name of guild",
|
"where_found": "Name of guild",
|
||||||
"reason": "Admin enters custom reason here"
|
"reason": "Admin enters custom reason here"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `feedback:<timestamp>-<DiscordUserID>-<DiscordUserName>`
|
- `feedback:<timestamp>-<DiscordUserID>-<DiscordUserName>`
|
||||||
- This is just a [String](https://redis.io/docs/latest/develop/data-types/strings/) containing whatever feedback they put in the feedback command
|
- This is just a [String](https://redis.io/docs/latest/develop/data-types/strings/) containing whatever feedback they put in the feedback command
|
||||||
- `guild-settings:<DiscordGuildID>`
|
- `guild-settings:<DiscordGuildID>`
|
||||||
- This is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry containing if the server has auto kick enabled or not as well as the channel id for bot announcements
|
- This is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry containing if the server has auto kick enabled or not as well as the channel ID for bot announcements
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -46,8 +46,8 @@ here are the "folders" and their descriptions:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `monitroted-guild:<DiscordGuildID>`
|
- `monitored-guild:<DiscordGuildID>`
|
||||||
- This is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry containing info about tracked servers. this is only inside of the `_deprecated.rs` as it was a hold over from the old Python verion's SQLite DB. more info about this one will come with the Python source code later™️
|
- This is a [JSON](https://redis.io/docs/latest/develop/data-types/json/) entry containing info about tracked servers. this is only inside of the `_deprecated.rs` as it was a holdover from the old Python version's SQLite DB. More info about this one will come with the Python source code later™️
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ here are the "folders" and their descriptions:
|
||||||
```
|
```
|
||||||
|
|
||||||
- `status:commands-executed`
|
- `status:commands-executed`
|
||||||
- this is a simple [String](https://redis.io/docs/latest/develop/data-types/strings/) entry to track how many commands have run since the feature was implemented, it appears at the bottom of the `/about` command
|
- This is a simple [String](https://redis.io/docs/latest/develop/data-types/strings/) entry to track how many commands have run since the feature was implemented, it appears at the bottom of the `/about` command
|
||||||
- `user:<DiscordUserID>`
|
- `user:<DiscordUserID>`
|
||||||
- This is the largest list of entries in the DB.
|
- This is the largest list of entries in the DB.
|
||||||
- These are [JSON](https://redis.io/docs/latest/develop/data-types/json/) entries for users who are uploaded via scrapped discords, more info on that in the next section
|
- These are [JSON](https://redis.io/docs/latest/develop/data-types/json/) entries for users who are uploaded via scrapped discords, more info on that in the next section
|
||||||
|
@ -84,24 +84,31 @@ here are the "folders" and their descriptions:
|
||||||
- `kick-whitelist`
|
- `kick-whitelist`
|
||||||
- This is a [SET](https://redis.io/docs/latest/develop/data-types/sets/) that I didn't put in a folder for some reason. It holds a list of DiscordUserIDs that should be ignored when running the `/excel` command.
|
- This is a [SET](https://redis.io/docs/latest/develop/data-types/sets/) that I didn't put in a folder for some reason. It holds a list of DiscordUserIDs that should be ignored when running the `/excel` command.
|
||||||
|
|
||||||
# scrape discords
|
# Scrape Discords
|
||||||
|
|
||||||
So the main use of this bot origionally was as follows:
|
So the main use of this bot originally was as follows:
|
||||||
|
|
||||||
- scrape discord using [DiscordChatExporter](https://github.com/Tyrrrz/DiscordChatExporter)
|
- scrape discord using [DiscordChatExporter](https://github.com/Tyrrrz/DiscordChatExporter)
|
||||||
- run resulting .csv files though [my old parser](https://github.com/BuyMyMojo/discord-chat-parser)
|
- run resulting .csv files through [my old parser](https://github.com/BuyMyMojo/discord-chat-parser)
|
||||||
- resulting file to the bot using the `/excel` command
|
- resulting file to the bot using the `/excel` command
|
||||||
|
|
||||||
This was to be used to scrape servers of bad actors such as VRC model rippers and leakers, it would add every user found inside the server into the DB with a description of the server that they are found in.
|
This was to be used to scrape servers of bad actors such as VRC model rippers and leakers, it would add every user found inside the server into the DB with a description of the server that they are found in.
|
||||||
|
|
||||||
Once in the DB whenever the user joined a server with the FBT bot active the server owner/mods would get notified of a bad actor joining or optionally it would auto kick these accounts.
|
Once in the DB whenever the user joined a server with the FBT bot active the server owner/mods would get notified of a bad actor joining or optionally it would auto-kick these accounts.
|
||||||
|
|
||||||
# that's all folks
|
# That's all folks
|
||||||
|
|
||||||
I might clean this up further or add a branch for the old python version in the future.
|
I might clean this up further or add a branch for the old Python version in the future.
|
||||||
|
|
||||||
good luck whoever may look upon my first large Rust project
|
good luck to whoever may look upon my first large Rust project
|
||||||
|
|
||||||
|
# Mirrors
|
||||||
|
|
||||||
|
- [GitHub](https://github.com/BuyMyMojo/open-fbt)
|
||||||
|
- [GitLab](https://gitlab.com/BuyMyMojo/open-fbt)
|
||||||
|
- [Codeberg](https://codeberg.org/BuyMyMojo/open-fbt)
|
||||||
|
- [Personal Gitea](https://git.buymymojo.net/BuyMyMojo/open-fbt)
|
||||||
|
|
||||||
<p style="color: rgba(0, 0, 0, 0)">
|
<p style="color: rgba(0, 0, 0, 0)">
|
||||||
There is no database files or user entries here, look somewhere else <3
|
There are no database files or user entries here, look somewhere else <3
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -187,6 +187,7 @@ pub async fn search(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
#[description = "Member to search for. This must be a user ID."] user_id: String,
|
#[description = "Member to search for. This must be a user ID."] user_id: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
use chrono::DateTime;
|
||||||
use pastemyst::paste::*;
|
use pastemyst::paste::*;
|
||||||
use pastemyst::str;
|
use pastemyst::str;
|
||||||
use poise::serenity_prelude::User;
|
use poise::serenity_prelude::User;
|
||||||
|
@ -381,12 +382,11 @@ pub async fn search(
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
||||||
let date_time_stamp = chrono::NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0)
|
let date_time_stamp = DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
.unwrap_or(chrono::NaiveDateTime::MIN);
|
|
||||||
|
|
||||||
let age = chrono::Utc::now()
|
let age = chrono::Utc::now()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
.signed_duration_since(date_time_stamp)
|
.signed_duration_since(date_time_stamp.naive_local())
|
||||||
.num_days();
|
.num_days();
|
||||||
|
|
||||||
let is_user_in_db: Option<String> = check_username_against_db(ctx.author().id.0).await.unwrap();
|
let is_user_in_db: Option<String> = check_username_against_db(ctx.author().id.0).await.unwrap();
|
||||||
|
@ -541,10 +541,10 @@ pub async fn update_search_engine(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
ctx.defer_ephemeral().await?;
|
ctx.defer_ephemeral().await?;
|
||||||
|
|
||||||
// Create a client (without sending any request so that can't fail)
|
// Create a client (without sending any request so that can't fail)
|
||||||
let client = Client::new(MEILISEARCH_HOST, MEILISEARCH_API_KEY);
|
let client = Client::new(MEILISEARCH_HOST, Some(MEILISEARCH_API_KEY));
|
||||||
|
|
||||||
// connect to index "entries"
|
// connect to index "entries"
|
||||||
let entries = client.index("entries");
|
let entries = client?.index("entries");
|
||||||
|
|
||||||
let msg = ctx
|
let msg = ctx
|
||||||
.send(|b| b.content("Connected to search engine"))
|
.send(|b| b.content("Connected to search engine"))
|
||||||
|
@ -626,6 +626,8 @@ pub async fn footprint_lookup(
|
||||||
BlacklistOutput,
|
BlacklistOutput,
|
||||||
>,
|
>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
use chrono::DateTime;
|
||||||
|
|
||||||
ctx.defer().await?;
|
ctx.defer().await?;
|
||||||
|
|
||||||
let mut con = open_redis_connection().await?;
|
let mut con = open_redis_connection().await?;
|
||||||
|
@ -929,12 +931,11 @@ pub async fn footprint_lookup(
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
||||||
let date_time_stamp = chrono::NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0)
|
let date_time_stamp = DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
.unwrap_or(chrono::NaiveDateTime::MIN);
|
|
||||||
|
|
||||||
let age = chrono::Utc::now()
|
let age = chrono::Utc::now()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
.signed_duration_since(date_time_stamp)
|
.signed_duration_since(date_time_stamp.naive_local())
|
||||||
.num_days();
|
.num_days();
|
||||||
|
|
||||||
let is_user_in_db: Option<String> =
|
let is_user_in_db: Option<String> =
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use chrono::NaiveDateTime;
|
use chrono::DateTime;
|
||||||
use poise::serenity_prelude::{self as serenity, AttachmentType, RichInvite};
|
use poise::serenity_prelude::{self as serenity, AttachmentType, RichInvite};
|
||||||
use rusted_fbt_lib::{
|
use rusted_fbt_lib::{
|
||||||
checks::guild_auth_check,
|
checks::guild_auth_check,
|
||||||
|
@ -26,11 +26,11 @@ pub async fn account_age(
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
||||||
let date_time_stamp =
|
let date_time_stamp =
|
||||||
NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0).unwrap_or(NaiveDateTime::MIN);
|
DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
|
|
||||||
let age = chrono::Utc::now()
|
let age = chrono::Utc::now()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
.signed_duration_since(date_time_stamp)
|
.signed_duration_since(date_time_stamp.naive_local())
|
||||||
.num_days();
|
.num_days();
|
||||||
|
|
||||||
ctx.say(format!(
|
ctx.say(format!(
|
||||||
|
@ -56,7 +56,7 @@ pub async fn creation_date(
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
||||||
let date_time_stamp =
|
let date_time_stamp =
|
||||||
NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0).unwrap_or(NaiveDateTime::MIN);
|
DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
|
|
||||||
ctx.say(format!("Created/Joined on {date_time_stamp}"))
|
ctx.say(format!("Created/Joined on {date_time_stamp}"))
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -277,11 +277,11 @@ pub async fn invite_info(
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
// this shouldn't be able to break but just in case I'm making the `unwrap_or` output NaiveDateTime::MIN
|
||||||
let date_time_stamp =
|
let date_time_stamp =
|
||||||
NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0).unwrap_or(NaiveDateTime::MIN);
|
DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
|
|
||||||
let age = chrono::Utc::now()
|
let age = chrono::Utc::now()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
.signed_duration_since(date_time_stamp)
|
.signed_duration_since(date_time_stamp.naive_local())
|
||||||
.num_days();
|
.num_days();
|
||||||
|
|
||||||
let is_user_in_db: Option<String> =
|
let is_user_in_db: Option<String> =
|
||||||
|
@ -293,7 +293,7 @@ pub async fn invite_info(
|
||||||
// TODO: set your own channel ID!
|
// TODO: set your own channel ID!
|
||||||
|
|
||||||
// log user name, id, guild name, id and url to channel
|
// log user name, id, guild name, id and url to channel
|
||||||
serenity::ChannelId()
|
serenity::ChannelId(00000000000000000)
|
||||||
.send_message(ctx, |f| {
|
.send_message(ctx, |f| {
|
||||||
f.embed(|e| {
|
f.embed(|e| {
|
||||||
e.title("User requested invite info")
|
e.title("User requested invite info")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::structs::{GuildSettings, UserInfo, WaybackResponse, WaybackStatus};
|
use crate::structs::{GuildSettings, UserInfo, WaybackResponse, WaybackStatus};
|
||||||
use crate::utils::snowflake_to_unix;
|
use crate::utils::snowflake_to_unix;
|
||||||
use crate::vars::FBT_GUILD_ID;
|
use crate::vars::FBT_GUILD_ID;
|
||||||
use chrono::NaiveDateTime;
|
// use chrono::NaiveDateTime;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use chrono_tz::Australia::Melbourne;
|
use chrono_tz::Australia::Melbourne;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
@ -90,6 +90,8 @@ pub async fn alt_kicker(
|
||||||
ctx: &serenity::Context,
|
ctx: &serenity::Context,
|
||||||
member: &serenity::Member,
|
member: &serenity::Member,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
use chrono::DateTime;
|
||||||
|
|
||||||
use crate::utils::open_redis_connection;
|
use crate::utils::open_redis_connection;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
@ -133,12 +135,11 @@ pub async fn alt_kicker(
|
||||||
|
|
||||||
#[allow(clippy::pedantic)]
|
#[allow(clippy::pedantic)]
|
||||||
// it literally only take's i64, no need to warn about truncation here.
|
// it literally only take's i64, no need to warn about truncation here.
|
||||||
let date_time_stamp = NaiveDateTime::from_timestamp_opt(unix_timecode as i64, 0)
|
let date_time_stamp = DateTime::from_timestamp(unix_timecode as i64, 0).unwrap_or(DateTime::UNIX_EPOCH);
|
||||||
.unwrap_or(NaiveDateTime::MIN);
|
|
||||||
|
|
||||||
let age = chrono::Utc::now()
|
let age = chrono::Utc::now()
|
||||||
.naive_utc()
|
.naive_utc()
|
||||||
.signed_duration_since(date_time_stamp)
|
.signed_duration_since(date_time_stamp.naive_local())
|
||||||
.num_days();
|
.num_days();
|
||||||
|
|
||||||
// Compare user age
|
// Compare user age
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub async fn pog_be_gone(
|
||||||
let mut hits: Vec<&str> = Vec::new();
|
let mut hits: Vec<&str> = Vec::new();
|
||||||
|
|
||||||
for word in words {
|
for word in words {
|
||||||
POG_RE.find(word).map_or((), |pog| {
|
let _ = POG_RE.find(word).map_or((), |pog| {
|
||||||
hits.push(pog.as_str());
|
hits.push(pog.as_str());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,9 @@ pub fn verbose_mode() -> bool {
|
||||||
/// Open a tokio redis connection
|
/// Open a tokio redis connection
|
||||||
#[cfg(feature = "database")]
|
#[cfg(feature = "database")]
|
||||||
#[instrument()]
|
#[instrument()]
|
||||||
pub async fn open_redis_connection() -> Result<redis::aio::Connection, anyhow::Error> {
|
pub async fn open_redis_connection() -> Result<redis::aio::MultiplexedConnection, anyhow::Error> {
|
||||||
let redis_connection = redis::Client::open(REDIS_ADDR)?
|
let redis_connection = redis::Client::open(REDIS_ADDR)?
|
||||||
.get_tokio_connection()
|
.get_multiplexed_tokio_connection()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(redis_connection)
|
Ok(redis_connection)
|
||||||
|
@ -38,7 +38,7 @@ pub async fn open_redis_connection() -> Result<redis::aio::Connection, anyhow::E
|
||||||
#[instrument(skip(con))]
|
#[instrument(skip(con))]
|
||||||
pub async fn set_guild_settings(
|
pub async fn set_guild_settings(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
con: &mut redis::aio::Connection,
|
con: &mut redis::aio::MultiplexedConnection,
|
||||||
settings: GuildSettings,
|
settings: GuildSettings,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let json = serde_json::to_string(&settings).unwrap();
|
let json = serde_json::to_string(&settings).unwrap();
|
||||||
|
@ -64,7 +64,7 @@ pub async fn set_guild_settings(
|
||||||
#[instrument(skip(con))]
|
#[instrument(skip(con))]
|
||||||
pub async fn auth(
|
pub async fn auth(
|
||||||
ctx: Context<'_>,
|
ctx: Context<'_>,
|
||||||
con: &mut redis::aio::Connection,
|
con: &mut redis::aio::MultiplexedConnection,
|
||||||
uid: String,
|
uid: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
redis::cmd("SADD")
|
redis::cmd("SADD")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue