Checkpoint
This commit is contained in:
@@ -4,28 +4,24 @@ use scc::HashSet;
|
||||
use time::UtcDateTime;
|
||||
use twilight_model::id::Id;
|
||||
|
||||
use crate::{
|
||||
database::models::{Call, Channel, Participant},
|
||||
discord::sanitizing::SanitizeDiscordMarkdown,
|
||||
extras::Extras,
|
||||
framework::commands::{
|
||||
Command, CommandError,
|
||||
arguments::{Arg, Argument, ParseArguments},
|
||||
context::CommandContext,
|
||||
permissions::Permission,
|
||||
},
|
||||
groups::calls::{
|
||||
masks::{get_mask_display_name, get_mask_emoji},
|
||||
permissions::{NonNewAccountPermission, NotBannedPermission},
|
||||
strings::{
|
||||
get_string_call_answered, get_string_call_hangup_other_party,
|
||||
get_string_call_hangup_this_party, get_string_call_no_answer,
|
||||
get_string_call_searching, get_string_tips,
|
||||
},
|
||||
},
|
||||
state::State,
|
||||
utils::Bye,
|
||||
use crate::database::models::{Call, Channel, Participant};
|
||||
use crate::discord::sanitizing::SanitizeDiscordMarkdown;
|
||||
use crate::extras::Extras;
|
||||
use crate::framework::commands::arguments::{Arg, Argument, ParseArguments};
|
||||
use crate::framework::commands::context::CommandContext;
|
||||
use crate::framework::commands::permissions::Permission;
|
||||
use crate::framework::commands::{Command, CommandError};
|
||||
use crate::groups::calls::masks::{get_mask_display_name, get_mask_emoji};
|
||||
use crate::groups::calls::permissions::{
|
||||
IsCallParticipantPermission, NonNewAccountPermission, NotBannedPermission,
|
||||
};
|
||||
use crate::groups::calls::strings::{
|
||||
get_string_call_answered, get_string_call_hangup_other_party,
|
||||
get_string_call_hangup_this_party, get_string_call_no_answer, get_string_call_searching,
|
||||
get_string_tips,
|
||||
};
|
||||
use crate::state::State;
|
||||
use crate::utils::Bye;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct CallCommand {
|
||||
@@ -172,8 +168,9 @@ impl Command<State, Extras> for SkipCommand {
|
||||
|
||||
fn permissions(&self) -> Vec<Box<dyn Permission<State, Extras> + Send + Sync + 'static>> {
|
||||
vec![
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(NonNewAccountPermission),
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(IsCallParticipantPermission),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -318,8 +315,9 @@ impl Command<State, Extras> for HangupCommand {
|
||||
|
||||
fn permissions(&self) -> Vec<Box<dyn Permission<State, Extras> + Send + Sync + 'static>> {
|
||||
vec![
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(NonNewAccountPermission),
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(IsCallParticipantPermission),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -442,8 +440,9 @@ impl Command<State, Extras> for FriendRequestCommand {
|
||||
|
||||
fn permissions(&self) -> Vec<Box<dyn Permission<State, Extras> + Send + Sync + 'static>> {
|
||||
vec![
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(NonNewAccountPermission),
|
||||
Box::new(NotBannedPermission),
|
||||
Box::new(IsCallParticipantPermission),
|
||||
]
|
||||
}
|
||||
|
||||
@@ -598,29 +597,28 @@ impl Command<State, Extras> for MaskCommand {
|
||||
mask_status, ctx.prefix, ctx.prefix
|
||||
);
|
||||
|
||||
if let Some(channel) = channel {
|
||||
if let Some(call_id) = channel.call_id {
|
||||
if let Some(mut participant) = Participant::get_for_user_and_channel_in_call(
|
||||
ctx.extras.user.id,
|
||||
ctx.event.channel_id.get(),
|
||||
call_id,
|
||||
&ctx.rt.state.db,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
participant.is_masked = ctx.extras.user.is_masked;
|
||||
participant.upsert(&ctx.rt.state.db).await?;
|
||||
if let Some(channel) = channel
|
||||
&& let Some(call_id) = channel.call_id
|
||||
{
|
||||
if let Some(mut participant) = Participant::get_for_user_and_channel_in_call(
|
||||
ctx.extras.user.id,
|
||||
ctx.event.channel_id.get(),
|
||||
call_id,
|
||||
&ctx.rt.state.db,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
participant.is_masked = ctx.extras.user.is_masked;
|
||||
participant.upsert(&ctx.rt.state.db).await?;
|
||||
|
||||
if ctx.extras.user.is_masked {
|
||||
mask_message = format!(
|
||||
"🎭 Your mask {mask_verb} set to `on`. You're currently being displayed as **{} {}**. You can toggle your mask on or off using `{}mask on` and `{}mask off`.",
|
||||
get_mask_emoji(&participant.user_mask)
|
||||
.expect("User's mask did not exist"),
|
||||
get_mask_display_name(&participant.user_mask),
|
||||
ctx.prefix,
|
||||
ctx.prefix
|
||||
);
|
||||
}
|
||||
if ctx.extras.user.is_masked {
|
||||
mask_message = format!(
|
||||
"🎭 Your mask {mask_verb} set to `on`. You're currently being displayed as **{} {}**. You can toggle your mask on or off using `{}mask on` and `{}mask off`.",
|
||||
get_mask_emoji(&participant.user_mask).expect("User's mask did not exist"),
|
||||
get_mask_display_name(&participant.user_mask),
|
||||
ctx.prefix,
|
||||
ctx.prefix
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{extras::Extras, framework::interactions::components::Button, state::State};
|
||||
use crate::extras::Extras;
|
||||
use crate::framework::interactions::components::Button;
|
||||
use crate::state::State;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CodeOfConductButton;
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use twilight_model::{channel::message::Embed, oauth::Application};
|
||||
use twilight_model::channel::message::Embed;
|
||||
use twilight_model::oauth::Application;
|
||||
use twilight_util::builder::embed::{
|
||||
EmbedAuthorBuilder, EmbedBuilder, EmbedFieldBuilder, EmbedFooterBuilder, ImageSource,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
constants::{COLOR_RED, COLOR_YELLOW},
|
||||
database::models::Message,
|
||||
discord::images,
|
||||
groups::calls::moderation::Rule,
|
||||
utils::ellipse,
|
||||
};
|
||||
use crate::constants::{COLOR_RED, COLOR_YELLOW};
|
||||
use crate::database::models::Message;
|
||||
use crate::discord::images;
|
||||
use crate::groups::calls::moderation::Rule;
|
||||
use crate::utils::ellipse;
|
||||
|
||||
pub fn first_warning_embed(
|
||||
app: &Application,
|
||||
|
||||
+68
-49
@@ -1,41 +1,36 @@
|
||||
use std::{error::Error, sync::Arc};
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use deadpool_redis::redis::AsyncTypedCommands;
|
||||
use itertools::Itertools;
|
||||
use time::{Duration, UtcDateTime};
|
||||
use twilight_http::{api_error::ApiError, error::ErrorType};
|
||||
use twilight_model::{
|
||||
gateway::payload::incoming::{MessageCreate, MessageDelete, MessageUpdate},
|
||||
id::Id,
|
||||
};
|
||||
use twilight_util::{
|
||||
builder::embed::{EmbedAuthorBuilder, EmbedBuilder, EmbedFooterBuilder, ImageSource},
|
||||
snowflake::Snowflake,
|
||||
use twilight_http::api_error::ApiError;
|
||||
use twilight_http::error::ErrorType;
|
||||
use twilight_model::gateway::payload::incoming::{MessageCreate, MessageDelete, MessageUpdate};
|
||||
use twilight_model::id::Id;
|
||||
use twilight_util::builder::embed::{
|
||||
EmbedAuthorBuilder, EmbedBuilder, EmbedFooterBuilder, ImageSource,
|
||||
};
|
||||
use twilight_util::snowflake::Snowflake;
|
||||
|
||||
use crate::{
|
||||
constants::{COLOR_WHITE, COLOR_YELLOW},
|
||||
database::models::{Call, Channel, Message, Participant, User, UserIncident},
|
||||
discord::{images, sanitizing::SanitizeDiscordMarkdown},
|
||||
extras::Extras,
|
||||
framework::{
|
||||
commands::extras::ExtrasGetter,
|
||||
events::traits::{
|
||||
EventResult, OnMessageDeleteHandler, OnMessageEditHandler, OnMessageHandler,
|
||||
},
|
||||
interactions::components::ActionRow,
|
||||
runtime::Runtime,
|
||||
},
|
||||
groups::calls::{
|
||||
components::{CodeOfConductButton, NeedHelpButton},
|
||||
embeds,
|
||||
masks::{get_mask_avatar_url, get_mask_display_name},
|
||||
moderation::{Action, Rule, escape_message, moderate_message},
|
||||
},
|
||||
state::State,
|
||||
utils::{ellipse, i64_to_u64},
|
||||
use crate::constants::{COLOR_WHITE, COLOR_YELLOW};
|
||||
use crate::database::models::{Call, Channel, Message, Participant, User, UserIncident};
|
||||
use crate::discord::images;
|
||||
use crate::discord::sanitizing::SanitizeDiscordMarkdown;
|
||||
use crate::extras::Extras;
|
||||
use crate::framework::commands::extras::ExtrasGetter;
|
||||
use crate::framework::events::traits::{
|
||||
EventResult, OnMessageDeleteHandler, OnMessageEditHandler, OnMessageHandler,
|
||||
};
|
||||
use crate::framework::interactions::components::ActionRow;
|
||||
use crate::framework::runtime::Runtime;
|
||||
use crate::groups::calls::components::{CodeOfConductButton, NeedHelpButton};
|
||||
use crate::groups::calls::embeds;
|
||||
use crate::groups::calls::masks::{get_mask_avatar_url, get_mask_display_name};
|
||||
use crate::groups::calls::moderation::{Action, Rule, escape_message, moderate_message};
|
||||
use crate::state::State;
|
||||
use crate::utils::{ellipse, i64_to_u64};
|
||||
|
||||
async fn penalize_user(
|
||||
user: User,
|
||||
@@ -349,15 +344,35 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
||||
)
|
||||
};
|
||||
|
||||
// Replied-to links are always
|
||||
// .../{other_party_server_id}/{other_party_channel_id}/{other_party_message_id}
|
||||
//
|
||||
// When the message being replied to was sent by the other party, the
|
||||
// `other_party_message_id` is the original message ID, given it was sent from
|
||||
// their channel so the original is in their channel.
|
||||
//
|
||||
// When the message being replied to was sent by this party, the
|
||||
// `other_party_message_id` is the propagation message ID given the other party
|
||||
// will have seen the propagated message instead.
|
||||
let message_link = if i64_to_u64(propagation_channel_id) == channel.id {
|
||||
// if the message replied-to was sent by the other party
|
||||
//
|
||||
// replied_to.message_id -> other party's channel id
|
||||
// replied_to.propagation_channel_id -> this channel's ID
|
||||
// replied_to.propagation_message_id -> this channel's message ID
|
||||
format!(
|
||||
"https://discord.com/channels/{}/{}/{}",
|
||||
opposite_channel.server_id, opposite_channel.id, replying_to.message_id
|
||||
)
|
||||
} else {
|
||||
// if the message replied-to was sent by this party
|
||||
//
|
||||
// replied_to.message_id -> this channel's message ID
|
||||
// replied_to.propagation_channel_id -> other party's channel id
|
||||
// replied_to.propagation_message_id -> other party's message ID
|
||||
format!(
|
||||
"https://discord.com/channels/{}/{}/{}",
|
||||
channel.server_id, propagation_channel_id, propagation_message_id
|
||||
opposite_channel.server_id, propagation_channel_id, propagation_message_id
|
||||
)
|
||||
};
|
||||
|
||||
@@ -377,7 +392,10 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
||||
.and_then(|i| i.color.map(|c| c as u32))
|
||||
.unwrap_or(COLOR_WHITE)
|
||||
})
|
||||
.description(ellipse(moderate_message(&replying_to.data.content, false).0, 100))
|
||||
.description(ellipse(
|
||||
moderate_message(&replying_to.data.content, false).0,
|
||||
100,
|
||||
))
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
@@ -440,12 +458,13 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
||||
error: ApiError::General(error),
|
||||
..
|
||||
} = e.kind()
|
||||
&& error.code == 10015 {
|
||||
log::debug!("Webhook not found, updating...");
|
||||
opposite_channel
|
||||
.update_webhook(&rt.state.db, &rt.http)
|
||||
.await?;
|
||||
}
|
||||
&& error.code == 10015
|
||||
{
|
||||
log::debug!("Webhook not found, updating...");
|
||||
opposite_channel
|
||||
.update_webhook(&rt.state.db, &rt.http)
|
||||
.await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
@@ -626,19 +645,19 @@ impl OnMessageDeleteHandler<State, Extras> for CallMessageDeleteHandler {
|
||||
&& let Some((webhook_id, webhook_token)) = opposite_channel
|
||||
.webhook_id
|
||||
.zip(opposite_channel.webhook_token)
|
||||
{
|
||||
rt.http
|
||||
.delete_webhook_message(
|
||||
Id::new(webhook_id),
|
||||
&webhook_token,
|
||||
Id::new(i64_to_u64(propagation_message_id)),
|
||||
)
|
||||
.await?;
|
||||
{
|
||||
rt.http
|
||||
.delete_webhook_message(
|
||||
Id::new(webhook_id),
|
||||
&webhook_token,
|
||||
Id::new(i64_to_u64(propagation_message_id)),
|
||||
)
|
||||
.await?;
|
||||
|
||||
message.data.is_deleted = true;
|
||||
message.data.is_deleted = true;
|
||||
|
||||
message.insert(&rt.state.db).await?;
|
||||
}
|
||||
message.insert(&rt.state.db).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@ goonbud
|
||||
goonbuds
|
||||
goonete
|
||||
goonetes
|
||||
gooner
|
||||
goonr
|
||||
goner
|
||||
boty hole
|
||||
suck my pp
|
||||
ass cracker
|
||||
@@ -95,6 +98,10 @@ masturbating
|
||||
masterbating
|
||||
masterbaiting
|
||||
masturbatigng
|
||||
masterbaiter
|
||||
mastrbaiter
|
||||
mastrbait
|
||||
mastrbate
|
||||
horny
|
||||
hrny
|
||||
whore / who re
|
||||
@@ -116,6 +123,8 @@ eat my bum
|
||||
eat mi bum
|
||||
ima touch you
|
||||
ima touch u
|
||||
i ma touch you
|
||||
i ma touch u
|
||||
il touch you
|
||||
il touch u
|
||||
im going to touch you
|
||||
@@ -125,4 +134,6 @@ im gonna touch u
|
||||
nude
|
||||
nudes
|
||||
nde
|
||||
ndes
|
||||
ndes
|
||||
nood
|
||||
noods
|
||||
@@ -83,7 +83,9 @@
|
||||
//!
|
||||
//! All of which would be detected.
|
||||
|
||||
use std::{collections::HashMap, fmt::Debug, sync::Arc};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::Itertools;
|
||||
use linkify::LinkFinder;
|
||||
|
||||
@@ -2,13 +2,13 @@ use async_trait::async_trait;
|
||||
use time::{Duration, UtcDateTime};
|
||||
use twilight_util::snowflake::Snowflake;
|
||||
|
||||
use crate::{
|
||||
database::models::UserIncident,
|
||||
extras::Extras,
|
||||
framework::commands::{CommandError, context::CommandContext, permissions::Permission},
|
||||
groups::calls::components::{CodeOfConductButton, NeedHelpButton},
|
||||
state::State,
|
||||
};
|
||||
use crate::database::models::{Call, Channel, Participant, UserIncident};
|
||||
use crate::extras::Extras;
|
||||
use crate::framework::commands::CommandError;
|
||||
use crate::framework::commands::context::CommandContext;
|
||||
use crate::framework::commands::permissions::Permission;
|
||||
use crate::groups::calls::components::{CodeOfConductButton, NeedHelpButton};
|
||||
use crate::state::State;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NotBannedPermission;
|
||||
@@ -72,3 +72,50 @@ impl Permission<State, Extras> for NonNewAccountPermission {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Requires users to have sent a message in the call to be able to use the command.
|
||||
///
|
||||
/// This is to prevent abuse of commands by lurkers in the call, as well as to prevent
|
||||
/// non-participants from skipping or ending calls they're not in.
|
||||
#[derive(Debug)]
|
||||
pub struct IsCallParticipantPermission;
|
||||
|
||||
#[async_trait]
|
||||
impl Permission<State, Extras> for IsCallParticipantPermission {
|
||||
async fn check(&self, ctx: &CommandContext<State, Extras>) -> Result<bool, CommandError> {
|
||||
let channel = match Channel::get_by_id(ctx.event.channel_id.get(), &ctx.rt.state.db).await?
|
||||
{
|
||||
Some(channel) => channel,
|
||||
None => return Ok(true), // The channel isn't in the database, so it can't be in call.
|
||||
};
|
||||
|
||||
let call_id = match channel.call_id {
|
||||
Some(call_id) => call_id,
|
||||
None => return Ok(true), // The channel isn't in a call, so the user can use commands in it.
|
||||
};
|
||||
|
||||
let participants = Participant::get_for_call(call_id, &ctx.rt.state.db).await?;
|
||||
|
||||
for participant in participants {
|
||||
if participant.user_id == ctx.event.author.id.get() {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
async fn on_handle_denied(
|
||||
&self,
|
||||
ctx: &CommandContext<State, Extras>,
|
||||
) -> Result<(), CommandError> {
|
||||
ctx.send()
|
||||
.content("❌ You haven't sent any messages on this call. You cannot run this command.")
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to send message: {e}");
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::{SeedableRng, seq::IndexedRandom};
|
||||
use rand::SeedableRng;
|
||||
use rand::seq::IndexedRandom;
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
|
||||
static STRINGS_TIPS: Lazy<Vec<String>> = Lazy::new(|| {
|
||||
|
||||
@@ -3,12 +3,11 @@ use deadpool_redis::redis::AsyncTypedCommands;
|
||||
use time::{Duration, UtcDateTime};
|
||||
use twilight_model::id::Id;
|
||||
|
||||
use crate::{
|
||||
database::models::Call,
|
||||
extras::Extras,
|
||||
framework::{runtime::Runtime, tasks::Task},
|
||||
state::State,
|
||||
};
|
||||
use crate::database::models::Call;
|
||||
use crate::extras::Extras;
|
||||
use crate::framework::runtime::Runtime;
|
||||
use crate::framework::tasks::Task;
|
||||
use crate::state::State;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EndInactiveCallsTask {
|
||||
|
||||
Reference in New Issue
Block a user