Merge branch 'dev'
This commit is contained in:
@@ -5,7 +5,7 @@ use once_cell::sync::Lazy;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use hex_color::HexColor;
|
use hex_color::HexColor;
|
||||||
use poise::serenity_prelude::{colours, Color, EditRole, Permissions};
|
use poise::serenity_prelude::{colours, Color, EditRole};
|
||||||
|
|
||||||
static COLORS: Lazy<HashMap<&'static str, Color>> = Lazy::new(|| {
|
static COLORS: Lazy<HashMap<&'static str, Color>> = Lazy::new(|| {
|
||||||
HashMap::from([
|
HashMap::from([
|
||||||
@@ -78,20 +78,8 @@ pub async fn color(ctx: Context<'_>, #[autocomplete = "autocomplete_colors"] col
|
|||||||
|
|
||||||
let user = ctx.author();
|
let user = ctx.author();
|
||||||
|
|
||||||
let mut tx = ctx.data().database.begin().await?;
|
let role = super::edit_role(ctx, user.id, guild, EditRole::new().colour(color), &ctx.data().database).await?;
|
||||||
|
common::no_ping_reply(&ctx, format!("{}'s color has been updated.", guild.role(ctx, role).await?)).await?;
|
||||||
if let Some(role) = super::get_user_role(user.id, guild, &mut *tx).await? {
|
|
||||||
let role = guild.role(ctx, role).await?;
|
|
||||||
guild.edit_role(ctx, role.id, EditRole::new().colour(color)).await?;
|
|
||||||
common::no_ping_reply(&ctx, format!("{}'s color has been updated.", role)).await?;
|
|
||||||
} else {
|
|
||||||
let role = guild.create_role(ctx, EditRole::new().colour(color).name(user.name.clone()).permissions(Permissions::empty())).await?;
|
|
||||||
super::update_user_role(user.id, guild, role.id, &mut *tx).await?;
|
|
||||||
let member = guild.member(ctx, user).await?;
|
|
||||||
member.add_role(ctx, role.id).await?;
|
|
||||||
tx.commit().await?;
|
|
||||||
common::no_ping_reply(&ctx, format!("{} has been given the new role {}.", user, role)).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
use crate::common::{Context, Error};
|
use crate::common::{Context, Error};
|
||||||
use sqlx::{PgExecutor, Row};
|
use sqlx::{PgExecutor, Row};
|
||||||
use poise::serenity_prelude::{RoleId, UserId, GuildId};
|
use poise::serenity_prelude::{EditRole, GuildId, Permissions, RoleId, UserId};
|
||||||
|
|
||||||
mod register;
|
mod register;
|
||||||
mod whois;
|
mod whois;
|
||||||
@@ -26,6 +26,42 @@ pub async fn role(_ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Edit a user's personal role, creates it with some default values if it doesn't exist.
|
||||||
|
pub async fn edit_role<'a, E>(ctx: Context<'a>, user: UserId, guild: GuildId, edit: EditRole<'a>, db: E) -> Result<RoleId, Error>
|
||||||
|
where E: PgExecutor<'a> + Clone,
|
||||||
|
{
|
||||||
|
if let Some(role) = get_user_role(user, guild, db.clone()).await? {
|
||||||
|
guild.role(ctx, role).await?.edit(ctx, edit).await?;
|
||||||
|
Ok(role)
|
||||||
|
} else {
|
||||||
|
create_role(ctx, user, guild, edit, db).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_role<'a, E>(ctx: Context<'a>, user: UserId, guild: GuildId, edit: EditRole<'a>, db: E) -> Result<RoleId, Error>
|
||||||
|
where E: PgExecutor<'a> + Clone,
|
||||||
|
{
|
||||||
|
let def = EditRole::new()
|
||||||
|
.name(user.to_user(ctx).await?.name)
|
||||||
|
.permissions(Permissions::empty())
|
||||||
|
.position({
|
||||||
|
match crate::commands::settings::get_positional_role(ctx, guild).await? {
|
||||||
|
Some(role) => guild.role(ctx, role).await?.position,
|
||||||
|
None => 0u16,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.hoist(crate::commands::settings::get_hoist_selfroles(ctx, guild).await?);
|
||||||
|
|
||||||
|
let member = guild.member(ctx, user).await?;
|
||||||
|
|
||||||
|
let mut role = guild.create_role(ctx, def).await?;
|
||||||
|
role.edit(ctx, edit).await?;
|
||||||
|
member.add_role(ctx, &role).await?;
|
||||||
|
update_user_role(user, guild, role.id, db).await?;
|
||||||
|
|
||||||
|
Ok(role.id)
|
||||||
|
}
|
||||||
|
|
||||||
/// Remove a row concerning a user's self role from the database
|
/// Remove a row concerning a user's self role from the database
|
||||||
pub async fn remove_user_role<'a, E>(user: UserId, guild: GuildId, db: E) -> Result<(), Error>
|
pub async fn remove_user_role<'a, E>(user: UserId, guild: GuildId, db: E) -> Result<(), Error>
|
||||||
where E: PgExecutor<'a>,
|
where E: PgExecutor<'a>,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
use crate::common::{self, Context, Error};
|
use crate::common::{self, Context, Error};
|
||||||
|
|
||||||
use poise::serenity_prelude::{EditRole, Permissions};
|
use poise::serenity_prelude::EditRole;
|
||||||
|
|
||||||
/// Change the name of your personal role
|
/// Change the name of your personal role
|
||||||
#[poise::command(slash_command, prefix_command)]
|
#[poise::command(slash_command, prefix_command)]
|
||||||
@@ -15,20 +15,8 @@ pub async fn name(ctx: Context<'_>, name: String) -> Result<(), Error> {
|
|||||||
|
|
||||||
let user = ctx.author();
|
let user = ctx.author();
|
||||||
|
|
||||||
let mut tx = ctx.data().database.begin().await?;
|
let role = super::edit_role(ctx, user.id, guild, EditRole::new().name(name), &ctx.data().database).await?;
|
||||||
|
common::no_ping_reply(&ctx, format!("{} has been updated.", guild.role(ctx, role).await?)).await?;
|
||||||
if let Some(role) = super::get_user_role(user.id, guild, &mut *tx).await? {
|
|
||||||
let role = guild.role(ctx, role).await?;
|
|
||||||
guild.edit_role(ctx, role.id, EditRole::new().name(name)).await?;
|
|
||||||
common::no_ping_reply(&ctx, format!("{} has been updated.", role)).await?;
|
|
||||||
} else {
|
|
||||||
let role = guild.create_role(ctx, EditRole::new().name(name).permissions(Permissions::empty())).await?;
|
|
||||||
super::update_user_role(user.id, guild, role.id, &mut *tx).await?;
|
|
||||||
let member = guild.member(ctx, user).await?;
|
|
||||||
member.add_role(ctx, role.id).await?;
|
|
||||||
tx.commit().await?;
|
|
||||||
common::no_ping_reply(&ctx, format!("{} has been given the new role {}.", user, role)).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,20 @@
|
|||||||
use crate::common::{Context, Error};
|
use crate::common::{Context, Error};
|
||||||
|
|
||||||
#[poise::command(prefix_command, slash_command, required_permissions = "MANAGE_GUILD")]
|
use poise::serenity_prelude::{Role, RoleId, GuildId};
|
||||||
async fn prefix(ctx: Context<'_>, prefix: String) -> Result<(), Error> {
|
use sqlx::Row;
|
||||||
|
|
||||||
|
async fn get_prefix(ctx: Context<'_>, guild: GuildId) -> Result<Option<String>, Error> {
|
||||||
|
let db = &ctx.data().database;
|
||||||
|
|
||||||
|
let prefix: Option<String> = sqlx::query("SELECT prefix FROM settings WHERE guildid = $1")
|
||||||
|
.bind(guild.get() as i64)
|
||||||
|
.fetch_one(db).await?.get(0);
|
||||||
|
|
||||||
|
Ok(prefix.or(ctx.data().prefix.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[poise::command(prefix_command, slash_command)]
|
||||||
|
async fn prefix(ctx: Context<'_>, prefix: Option<String>) -> Result<(), Error> {
|
||||||
let guild = match ctx.guild_id() {
|
let guild = match ctx.guild_id() {
|
||||||
Some(g) => g,
|
Some(g) => g,
|
||||||
None => {
|
None => {
|
||||||
@@ -10,6 +23,15 @@ async fn prefix(ctx: Context<'_>, prefix: String) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match prefix {
|
||||||
|
Some(prefix) => {
|
||||||
|
let member = ctx.author_member().await.unwrap();
|
||||||
|
|
||||||
|
if !member.permissions(ctx).iter().any(|p| p.manage_guild()) {
|
||||||
|
ctx.reply("You do not have permission to change this setting.").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let mut tx = ctx.data().database.begin().await?;
|
let mut tx = ctx.data().database.begin().await?;
|
||||||
|
|
||||||
sqlx::query("INSERT INTO settings (guildid, prefix) VALUES ($1, $2) ON CONFLICT (guildid) DO UPDATE SET prefix = EXCLUDED.prefix")
|
sqlx::query("INSERT INTO settings (guildid, prefix) VALUES ($1, $2) ON CONFLICT (guildid) DO UPDATE SET prefix = EXCLUDED.prefix")
|
||||||
@@ -20,11 +42,128 @@ async fn prefix(ctx: Context<'_>, prefix: String) -> Result<(), Error> {
|
|||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
|
|
||||||
ctx.reply(format!("This server's custom prefix has been updated to `{prefix}`.")).await?;
|
ctx.reply(format!("This server's custom prefix has been updated to `{prefix}`.")).await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let s = get_prefix(ctx, guild).await?.map(|s| format!("`{s}`")).unwrap_or("not set".into());
|
||||||
|
ctx.reply(format!("This server's command prefix is {s}.")).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[poise::command(prefix_command, slash_command, subcommands("prefix"), subcommand_required)]
|
pub async fn get_positional_role(ctx: Context<'_>, guild: GuildId) -> Result<Option<RoleId>, Error> {
|
||||||
|
let db = &ctx.data().database;
|
||||||
|
|
||||||
|
let role: Option<i64> = sqlx::query("SELECT positional_role FROM settings WHERE guildid = $1")
|
||||||
|
.bind(guild.get() as i64)
|
||||||
|
.fetch_one(db).await?.get(0);
|
||||||
|
|
||||||
|
Ok(role.map(|sf| RoleId::new(sf as u64)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[poise::command(prefix_command, slash_command)]
|
||||||
|
pub async fn position(ctx: Context<'_>, role: Option<Role>) -> Result<(), Error> {
|
||||||
|
let guild = match ctx.guild_id() {
|
||||||
|
Some(g) => g,
|
||||||
|
None => {
|
||||||
|
ctx.reply("This command must be ran within a guild.").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let member = ctx.author_member().await.unwrap();
|
||||||
|
|
||||||
|
if !member.permissions(ctx).iter().any(|p| p.manage_guild()) {
|
||||||
|
ctx.reply("You do not have permission to see or change this setting.").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
match role {
|
||||||
|
Some(role) => {
|
||||||
|
let mut tx = ctx.data().database.begin().await?;
|
||||||
|
|
||||||
|
sqlx::query("INSERT INTO settings (guildid, positional_role) VALUES ($1, $2) ON CONFLICT (guildid) DO UPDATE SET positional_role = EXCLUDED.positional_role")
|
||||||
|
.bind(guild.get() as i64)
|
||||||
|
.bind(role.id.get() as i64)
|
||||||
|
.execute(&mut *tx).await?;
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
|
|
||||||
|
ctx.reply(format!("The bot will now place newly created self roles below `{role}`.")).await?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let s = match get_positional_role(ctx, guild).await? {
|
||||||
|
Some(r) => format!("{}", guild.role(ctx, r).await?),
|
||||||
|
None => "not set".into()
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.reply(format!("This server's positional role is {s}.")).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_hoist_selfroles(ctx: Context<'_>, guild: GuildId) -> Result<bool, Error> {
|
||||||
|
let db = &ctx.data().database;
|
||||||
|
|
||||||
|
let hoist: Option<bool> = sqlx::query("SELECT hoist_selfroles FROM settings WHERE guildid = $1")
|
||||||
|
.bind(guild.get() as i64)
|
||||||
|
.fetch_one(db).await?.get(0);
|
||||||
|
|
||||||
|
Ok(hoist.unwrap_or(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[poise::command(prefix_command, slash_command)]
|
||||||
|
pub async fn hoist(ctx: Context<'_>, hoist: Option<bool>) -> Result<(), Error> {
|
||||||
|
let guild = match ctx.guild_id() {
|
||||||
|
Some(g) => g,
|
||||||
|
None => {
|
||||||
|
ctx.reply("This command must be ran within a guild.").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match hoist {
|
||||||
|
Some(hoist) => {
|
||||||
|
let member = ctx.author_member().await.unwrap();
|
||||||
|
|
||||||
|
if !member.permissions(ctx).iter().any(|p| p.manage_guild()) {
|
||||||
|
ctx.reply("You do not have permission to change this setting.").await?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tx = ctx.data().database.begin().await?;
|
||||||
|
|
||||||
|
sqlx::query("INSERT INTO settings (guildid, hoist_selfroles) VALUES ($1, $2) ON CONFLICT (guildid) DO UPDATE SET hoist_selfroles = EXCLUDED.hoist_selfroles")
|
||||||
|
.bind(guild.get() as i64)
|
||||||
|
.bind(hoist)
|
||||||
|
.execute(&mut *tx).await?;
|
||||||
|
|
||||||
|
tx.commit().await?;
|
||||||
|
|
||||||
|
if hoist {
|
||||||
|
ctx.reply("New self roles will now be automatically hoisted.").await?;
|
||||||
|
} else {
|
||||||
|
ctx.reply("New self roles will not be hoisted.").await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let s = if get_hoist_selfroles(ctx, guild).await? {
|
||||||
|
"enabled"
|
||||||
|
} else {
|
||||||
|
"disabled"
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.reply(format!("Hoisting selfroles is {s}.")).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[poise::command(prefix_command, slash_command, subcommands("prefix", "position", "hoist"), subcommand_required)]
|
||||||
pub async fn setting(_ctx: Context<'_>) -> Result<(), Error> {
|
pub async fn setting(_ctx: Context<'_>) -> Result<(), Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
11
src/main.rs
11
src/main.rs
@@ -17,7 +17,7 @@ use sqlx::Row;
|
|||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
struct BotArgs {
|
struct BotArgs {
|
||||||
/// Prefix for the bot (if unspecified, the bot will not have one)
|
/// Prefix for the bot. If unspecified, the bot will not have one and will also not have access to message content.
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
prefix: Option<String>,
|
prefix: Option<String>,
|
||||||
}
|
}
|
||||||
@@ -62,12 +62,11 @@ async fn get_prefix(ctx: PartialContext<'_, Data, Error>) -> Result<Option<Strin
|
|||||||
|
|
||||||
let db = &ctx.data.database;
|
let db = &ctx.data.database;
|
||||||
|
|
||||||
let prefix = sqlx::query("SELECT prefix FROM settings WHERE guildid = $1")
|
let prefix: Option<String> = sqlx::query("SELECT prefix FROM settings WHERE guildid = $1")
|
||||||
.bind(guild.get() as i64)
|
.bind(guild.get() as i64)
|
||||||
.fetch_one(db).await.ok()
|
.fetch_one(db).await?.get(0);
|
||||||
.map(|x| x.get(0)).unwrap_or(ctx.data.prefix.clone());
|
|
||||||
|
|
||||||
Ok(prefix)
|
Ok(prefix.or(ctx.data.prefix.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
@@ -164,6 +163,8 @@ async fn main() -> Result<(), Error> {
|
|||||||
r#"
|
r#"
|
||||||
CREATE TABLE IF NOT EXISTS settings (
|
CREATE TABLE IF NOT EXISTS settings (
|
||||||
guildid BIGINT NOT NULL PRIMARY KEY,
|
guildid BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
positional_role BIGINT,
|
||||||
|
hoist_selfroles BOOLEAN,
|
||||||
prefix TEXT
|
prefix TEXT
|
||||||
)
|
)
|
||||||
"#
|
"#
|
||||||
|
|||||||
Reference in New Issue
Block a user