Favorite/unfavorite sounds
This commit is contained in:
parent
92d8d077df
commit
e875038851
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="dataSourceStorageLocal" created-in="CL-231.9161.40">
|
<component name="dataSourceStorageLocal" created-in="CL-231.8109.174">
|
||||||
<data-source name="MySQL for 5.1 - soundfx@localhost" uuid="1067c1d0-1386-4a39-b3f5-6d48d6f279eb">
|
<data-source name="MySQL for 5.1 - soundfx@localhost" uuid="1067c1d0-1386-4a39-b3f5-6d48d6f279eb">
|
||||||
<database-info product="" version="" jdbc-version="" driver-name="" driver-version="" dbms="MYSQL" exact-version="0" />
|
<database-info product="" version="" jdbc-version="" driver-name="" driver-version="" dbms="MYSQL" exact-version="0" />
|
||||||
<secret-storage>master_key</secret-storage>
|
<secret-storage>master_key</secret-storage>
|
||||||
|
8
migrations/20230816145151_favorite_sounds.sql
Normal file
8
migrations/20230816145151_favorite_sounds.sql
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
ALTER TABLE users ADD PRIMARY KEY (`user`);
|
||||||
|
|
||||||
|
CREATE TABLE favorite_sounds (
|
||||||
|
user_id BIGINT UNSIGNED NOT NULL,
|
||||||
|
sound_id INT UNSIGNED NOT NULL,
|
||||||
|
FOREIGN KEY (sound_id) REFERENCES `sounds`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
PRIMARY KEY (user_id, sound_id)
|
||||||
|
);
|
96
src/cmds/favorite.rs
Normal file
96
src/cmds/favorite.rs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
use log::warn;
|
||||||
|
|
||||||
|
use crate::{cmds::autocomplete_sound, models::sound::SoundCtx, Context, Error};
|
||||||
|
|
||||||
|
#[poise::command(slash_command, rename = "favorites", guild_only = true)]
|
||||||
|
pub async fn favorites(_ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a sound as a favorite
|
||||||
|
#[poise::command(
|
||||||
|
slash_command,
|
||||||
|
rename = "add",
|
||||||
|
category = "Favorites",
|
||||||
|
guild_only = true
|
||||||
|
)]
|
||||||
|
pub async fn add_favorite(
|
||||||
|
ctx: Context<'_>,
|
||||||
|
#[description = "Name or ID of sound to favorite"]
|
||||||
|
#[autocomplete = "autocomplete_sound"]
|
||||||
|
name: String,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let sounds = ctx
|
||||||
|
.data()
|
||||||
|
.search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match sounds {
|
||||||
|
Ok(sounds) => {
|
||||||
|
let sound = &sounds[0];
|
||||||
|
|
||||||
|
sound
|
||||||
|
.add_favorite(ctx.author().id, &ctx.data().database)
|
||||||
|
.await?;
|
||||||
|
ctx.say(format!(
|
||||||
|
"Sound {} (ID {}) added to favorites.",
|
||||||
|
sound.name, sound.id
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Couldn't fetch sounds: {:?}", e);
|
||||||
|
|
||||||
|
ctx.say("Failed to find sound.").await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a sound from your favorites
|
||||||
|
#[poise::command(
|
||||||
|
slash_command,
|
||||||
|
rename = "remove",
|
||||||
|
category = "Favorites",
|
||||||
|
guild_only = true
|
||||||
|
)]
|
||||||
|
pub async fn remove_favorite(
|
||||||
|
ctx: Context<'_>,
|
||||||
|
#[description = "Name or ID of sound to favorite"]
|
||||||
|
#[autocomplete = "autocomplete_sound"]
|
||||||
|
name: String,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let sounds = ctx
|
||||||
|
.data()
|
||||||
|
.search_for_sound(&name, ctx.guild_id().unwrap(), ctx.author().id, true)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match sounds {
|
||||||
|
Ok(sounds) => {
|
||||||
|
let sound = &sounds[0];
|
||||||
|
|
||||||
|
sound
|
||||||
|
.remove_favorite(ctx.author().id, &ctx.data().database)
|
||||||
|
.await?;
|
||||||
|
ctx.say(format!(
|
||||||
|
"Sound {} (ID {}) removed from favorites.",
|
||||||
|
sound.name, sound.id
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Couldn't fetch sounds: {:?}", e);
|
||||||
|
|
||||||
|
ctx.say("Failed to find sound.").await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,9 @@ __Library Commands__
|
|||||||
`/public` - Set a sound as public/private
|
`/public` - Set a sound as public/private
|
||||||
`/list server` - List sounds on this server
|
`/list server` - List sounds on this server
|
||||||
`/list user` - List your sounds
|
`/list user` - List your sounds
|
||||||
|
`/favorites add` - Add a favorite
|
||||||
|
`/favorites remove` - Remove a favorite
|
||||||
|
`/list favorites` - List favorites
|
||||||
|
|
||||||
__Search Commands__
|
__Search Commands__
|
||||||
`/search` - Search for public sounds by name
|
`/search` - Search for public sounds by name
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{models::sound::SoundCtx, Context};
|
use crate::{models::sound::SoundCtx, Context};
|
||||||
|
|
||||||
|
pub mod favorite;
|
||||||
pub mod info;
|
pub mod info;
|
||||||
pub mod manage;
|
pub mod manage;
|
||||||
pub mod play;
|
pub mod play;
|
||||||
|
@ -47,12 +47,14 @@ pub async fn list_sounds(_ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
enum ListContext {
|
enum ListContext {
|
||||||
User = 0,
|
User = 0,
|
||||||
Guild = 1,
|
Guild = 1,
|
||||||
|
Favorite = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListContext {
|
impl ListContext {
|
||||||
pub fn title(&self) -> &'static str {
|
pub fn title(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
ListContext::User => "Your sounds",
|
ListContext::User => "Your sounds",
|
||||||
|
ListContext::Favorite => "Your favorite sounds",
|
||||||
ListContext::Guild => "Server sounds",
|
ListContext::Guild => "Server sounds",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,6 +88,20 @@ pub async fn list_user_sounds(ctx: Context<'_>) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show all sounds you have uploaded
|
||||||
|
#[poise::command(slash_command, rename = "user", guild_only = true)]
|
||||||
|
pub async fn list_favorite_sounds(ctx: Context<'_>) -> Result<(), Error> {
|
||||||
|
let pager = SoundPager {
|
||||||
|
nonce: 0,
|
||||||
|
page: 0,
|
||||||
|
context: ListContext::Favorite,
|
||||||
|
};
|
||||||
|
|
||||||
|
pager.reply(ctx).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SoundPager {
|
pub struct SoundPager {
|
||||||
nonce: u64,
|
nonce: u64,
|
||||||
@ -102,6 +118,7 @@ impl SoundPager {
|
|||||||
) -> Result<Vec<Sound>, sqlx::Error> {
|
) -> Result<Vec<Sound>, sqlx::Error> {
|
||||||
match self.context {
|
match self.context {
|
||||||
ListContext::User => data.user_sounds(user_id, Some(self.page)).await,
|
ListContext::User => data.user_sounds(user_id, Some(self.page)).await,
|
||||||
|
ListContext::Favorite => data.favorite_sounds(user_id, Some(self.page)).await,
|
||||||
ListContext::Guild => data.guild_sounds(guild_id, Some(self.page)).await,
|
ListContext::Guild => data.guild_sounds(guild_id, Some(self.page)).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,6 +222,7 @@ impl SoundPager {
|
|||||||
let sounds = pager.get_page(data, user_id, guild_id).await?;
|
let sounds = pager.get_page(data, user_id, guild_id).await?;
|
||||||
let count = match pager.context {
|
let count = match pager.context {
|
||||||
ListContext::User => data.count_user_sounds(user_id).await?,
|
ListContext::User => data.count_user_sounds(user_id).await?,
|
||||||
|
ListContext::Favorite => data.count_favorite_sounds(user_id).await?,
|
||||||
ListContext::Guild => data.count_guild_sounds(guild_id).await?,
|
ListContext::Guild => data.count_guild_sounds(guild_id).await?,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -228,6 +246,7 @@ impl SoundPager {
|
|||||||
.await?;
|
.await?;
|
||||||
let count = match self.context {
|
let count = match self.context {
|
||||||
ListContext::User => ctx.data().count_user_sounds(ctx.author().id).await?,
|
ListContext::User => ctx.data().count_user_sounds(ctx.author().id).await?,
|
||||||
|
ListContext::Favorite => ctx.data().count_favorite_sounds(ctx.author().id).await?,
|
||||||
ListContext::Guild => {
|
ListContext::Guild => {
|
||||||
ctx.data()
|
ctx.data()
|
||||||
.count_guild_sounds(ctx.guild_id().unwrap())
|
.count_guild_sounds(ctx.guild_id().unwrap())
|
||||||
|
@ -92,9 +92,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
subcommands: vec![
|
subcommands: vec![
|
||||||
cmds::search::list_guild_sounds(),
|
cmds::search::list_guild_sounds(),
|
||||||
cmds::search::list_user_sounds(),
|
cmds::search::list_user_sounds(),
|
||||||
|
cmds::search::list_favorite_sounds(),
|
||||||
],
|
],
|
||||||
..cmds::search::list_sounds()
|
..cmds::search::list_sounds()
|
||||||
},
|
},
|
||||||
|
poise::Command {
|
||||||
|
subcommands: vec![
|
||||||
|
cmds::favorite::add_favorite(),
|
||||||
|
cmds::favorite::remove_favorite(),
|
||||||
|
],
|
||||||
|
..cmds::favorite::favorites()
|
||||||
|
},
|
||||||
cmds::search::show_random_sounds(),
|
cmds::search::show_random_sounds(),
|
||||||
cmds::search::search_sounds(),
|
cmds::search::search_sounds(),
|
||||||
cmds::stop::stop_playing(),
|
cmds::stop::stop_playing(),
|
||||||
|
@ -42,12 +42,21 @@ pub trait SoundCtx {
|
|||||||
user_id: U,
|
user_id: U,
|
||||||
page: Option<u64>,
|
page: Option<u64>,
|
||||||
) -> Result<Vec<Sound>, sqlx::Error>;
|
) -> Result<Vec<Sound>, sqlx::Error>;
|
||||||
|
async fn favorite_sounds<U: Into<u64> + Send>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
page: Option<u64>,
|
||||||
|
) -> Result<Vec<Sound>, sqlx::Error>;
|
||||||
async fn guild_sounds<G: Into<u64> + Send>(
|
async fn guild_sounds<G: Into<u64> + Send>(
|
||||||
&self,
|
&self,
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
page: Option<u64>,
|
page: Option<u64>,
|
||||||
) -> Result<Vec<Sound>, sqlx::Error>;
|
) -> Result<Vec<Sound>, sqlx::Error>;
|
||||||
async fn count_user_sounds<U: Into<u64> + Send>(&self, user_id: U) -> Result<u64, sqlx::Error>;
|
async fn count_user_sounds<U: Into<u64> + Send>(&self, user_id: U) -> Result<u64, sqlx::Error>;
|
||||||
|
async fn count_favorite_sounds<U: Into<u64> + Send>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
) -> Result<u64, sqlx::Error>;
|
||||||
async fn count_guild_sounds<G: Into<u64> + Send>(
|
async fn count_guild_sounds<G: Into<u64> + Send>(
|
||||||
&self,
|
&self,
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
@ -219,6 +228,50 @@ SELECT name, id, public, server_id, uploader_id
|
|||||||
Ok(sounds)
|
Ok(sounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn favorite_sounds<U: Into<u64> + Send>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
page: Option<u64>,
|
||||||
|
) -> Result<Vec<Sound>, sqlx::Error> {
|
||||||
|
let sounds = match page {
|
||||||
|
Some(page) => {
|
||||||
|
sqlx::query_as_unchecked!(
|
||||||
|
Sound,
|
||||||
|
"
|
||||||
|
SELECT name, id, public, server_id, uploader_id
|
||||||
|
FROM sounds
|
||||||
|
INNER JOIN favorite_sounds f ON sounds.id = f.sound_id
|
||||||
|
WHERE f.user_id = ?
|
||||||
|
ORDER BY id DESC
|
||||||
|
LIMIT ?, ?
|
||||||
|
",
|
||||||
|
user_id.into(),
|
||||||
|
page * 25,
|
||||||
|
(page + 1) * 25
|
||||||
|
)
|
||||||
|
.fetch_all(&self.database)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
sqlx::query_as_unchecked!(
|
||||||
|
Sound,
|
||||||
|
"
|
||||||
|
SELECT name, id, public, server_id, uploader_id
|
||||||
|
FROM sounds
|
||||||
|
INNER JOIN favorite_sounds f ON sounds.id = f.sound_id
|
||||||
|
WHERE f.user_id = ?
|
||||||
|
ORDER BY id DESC
|
||||||
|
",
|
||||||
|
user_id.into()
|
||||||
|
)
|
||||||
|
.fetch_all(&self.database)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(sounds)
|
||||||
|
}
|
||||||
|
|
||||||
async fn guild_sounds<G: Into<u64> + Send>(
|
async fn guild_sounds<G: Into<u64> + Send>(
|
||||||
&self,
|
&self,
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
@ -272,6 +325,19 @@ SELECT name, id, public, server_id, uploader_id
|
|||||||
.count as u64)
|
.count as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn count_favorite_sounds<U: Into<u64> + Send>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
) -> Result<u64, sqlx::Error> {
|
||||||
|
Ok(sqlx::query!(
|
||||||
|
"SELECT COUNT(1) as count FROM favorite_sounds WHERE user_id = ?",
|
||||||
|
user_id.into()
|
||||||
|
)
|
||||||
|
.fetch_one(&self.database)
|
||||||
|
.await?
|
||||||
|
.count as u64)
|
||||||
|
}
|
||||||
|
|
||||||
async fn count_guild_sounds<G: Into<u64> + Send>(
|
async fn count_guild_sounds<G: Into<u64> + Send>(
|
||||||
&self,
|
&self,
|
||||||
guild_id: G,
|
guild_id: G,
|
||||||
@ -416,6 +482,42 @@ WHERE
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn add_favorite<U: Into<u64>>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
db_pool: impl Executor<'_, Database = Database>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync + Send>> {
|
||||||
|
let user_id = user_id.into();
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"INSERT INTO favorite_sounds (user_id, sound_id) VALUES (?, ?)",
|
||||||
|
user_id,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.execute(db_pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn remove_favorite<U: Into<u64>>(
|
||||||
|
&self,
|
||||||
|
user_id: U,
|
||||||
|
db_pool: impl Executor<'_, Database = Database>,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync + Send>> {
|
||||||
|
let user_id = user_id.into();
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"DELETE FROM favorite_sounds WHERE user_id = ? AND sound_id = ?",
|
||||||
|
user_id,
|
||||||
|
self.id
|
||||||
|
)
|
||||||
|
.execute(db_pool)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_anon<G: Into<u64>, U: Into<u64>>(
|
pub async fn create_anon<G: Into<u64>, U: Into<u64>>(
|
||||||
name: &str,
|
name: &str,
|
||||||
src_url: &str,
|
src_url: &str,
|
||||||
|
Loading…
Reference in New Issue
Block a user