From c08ec0120d696c2841c7516babd090743a066a35 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 11 Feb 2024 18:39:09 -0700 Subject: [PATCH] Added picox support! --- Cargo.lock | 14 ++- Cargo.toml | 5 +- src/album_manager/mod.rs | 262 +++++++++++++++++++++++++-------------- src/config.rs | 12 +- src/discord/album.rs | 157 ++++------------------- src/discord/joke.rs | 37 +++--- src/discord/motivate.rs | 29 ++++- src/discord/shop.rs | 2 +- src/error.rs | 8 ++ src/models/motivation.rs | 32 ++--- 10 files changed, 288 insertions(+), 270 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 172949b..2459e6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,6 +761,7 @@ dependencies = [ "regex", "reqwest", "serde", + "serde_json", "serenity", "sha3", "songbird", @@ -2062,9 +2063,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ "base64 0.21.7", "bytes", @@ -2091,6 +2092,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -2431,9 +2433,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -3661,9 +3663,9 @@ checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "wasm-streams" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4609d447824375f43e1ffbc051b50ad8f4b3ae8219680c94452ea05eb240ac7" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" dependencies = [ "futures-util", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index a41415e..f9dcaf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "0.5.0" +version = "0.5.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -8,7 +8,7 @@ edition = "2021" [dependencies] config = "0.13.4" structopt = "0.3.26" -reqwest = { version = "0.11.23", features = ["json"] } +reqwest = { version = "0.11.24", features = ["json"] } serde = "1.0.195" toml = "0.8.8" rand = "0.8.5" @@ -26,6 +26,7 @@ j_db = { version = "0.1.0", registry = "jojo-dev" } chrono = { version = "0.4.31", features = ["serde"] } chrono-tz = "0.8.5" log = "0.4.20" +serde_json = "1.0.113" [dependencies.serenity] version = "0.12.0" diff --git a/src/album_manager/mod.rs b/src/album_manager/mod.rs index a7a12c4..b3c689c 100644 --- a/src/album_manager/mod.rs +++ b/src/album_manager/mod.rs @@ -1,126 +1,198 @@ use crate::error::Error; -use j_db::database::Database; -use j_db::error::JDbError; -use j_db::model::JdbModel; -use rand::prelude::SliceRandom; -use reqwest::Url; +use chrono::{DateTime, Utc}; +use reqwest::multipart::{Form, Part}; +use reqwest::{Client, Url}; use serde::{Deserialize, Serialize}; -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; -use std::path::PathBuf; -#[derive(Debug, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CreateAlbum { + pub album_name: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Image { pub filename: String, pub tags: Vec, - pub hash: u64, - pub db_name: String, + pub create_date: DateTime, + pub link: Url, + pub created_by: u64, + pub album: u64, + pub id: u64, } -impl Image { - pub async fn new(data: &[u8], filename: &str, base_dir: PathBuf, tags: Vec) -> Self { - let mut hasher = DefaultHasher::new(); - data.hash(&mut hasher); - filename.hash(&mut hasher); - let hash = hasher.finish(); - let file = PathBuf::from(filename); - let ext = file.extension().unwrap().to_str().unwrap(); +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AlbumQuery { + pub album_name: Option, +} - let db_name = format!("{}.{}", hash, ext); - let path = base_dir.join(db_name.clone()); - tokio::fs::write(path, data).await.unwrap(); +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AddImage { + pub album: AlbumQuery, + pub tags: Vec, +} - Self { - filename: filename.to_string(), - tags, - hash, - db_name, - } - } +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub enum ImageSort { + Random, + DateAscending, + DateDescending, + #[default] + None, +} - pub fn full_path(&self, base_dir: PathBuf) -> PathBuf { - base_dir.join(&self.db_name) - } - - pub fn link(&self, base_link: &Url) -> Url { - base_link.join(&self.db_name).unwrap() - } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImageQuery { + pub album: Option, + #[serde(default)] + pub tags: Vec, + #[serde(default)] + pub order: ImageSort, + #[serde(default)] + pub limit: usize, } #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Album { - id: Option, pub album_name: String, - pub images: Vec, + pub images: Vec, pub aliases: Vec, + pub created_at: DateTime, + pub modified_at: DateTime, + pub owner: u64, + pub id: u64, } -impl Album { - pub fn find_album_by_name_or_alias( - db: &Database, - name: &str, - ) -> Result, JDbError> { - Ok(db - .filter(|_, album: &Album| { - album.album_name.eq_ignore_ascii_case(name) - || album.aliases.contains(&name.to_string()) - })? - .next()) +#[derive(Debug, Clone)] +pub struct AlbumManager { + api_client: Client, + base_url: Url, + token: String, +} + +impl AlbumManager { + pub fn new(base_url: Url, token: &str) -> Self { + Self { + api_client: Client::new(), + base_url, + token: token.to_string(), + } } - pub fn get_random_image( - db: &Database, + pub async fn query_album(&self, query: AlbumQuery) -> Result, Error> { + let resp = self + .api_client + .get(self.base_url.join("api/album/").unwrap()) + .query(&query) + .send() + .await?; + + Ok(resp.json().await?) + } + + pub async fn get_album_by_id(&self, id: u64) -> Result { + Ok(self + .api_client + .get( + self.base_url + .join("api/album/") + .unwrap() + .join(&id.to_string()) + .unwrap(), + ) + .send() + .await? + .json() + .await?) + } + + pub async fn query_image(&self, query: ImageQuery) -> Result, Error> { + let url = self.base_url.join("api/image/").unwrap(); + Ok(self + .api_client + .get(url) + .json(&query) + .send() + .await + .unwrap() + .json() + .await?) + } + + pub async fn get_image_by_id(&self, id: u64) -> Result { + let url = self + .base_url + .join("api/image/") + .unwrap() + .join(&id.to_string()) + .unwrap(); + Ok(self.api_client.get(url).send().await?.json().await?) + } + + pub async fn get_random_image( + &self, album_name: &str, tags: Vec<&str>, ) -> Result, Error> { - let mut rng = rand::thread_rng(); - let album = match Self::find_album_by_name_or_alias(db, album_name)? { - None => return Err(Error::NoAlbumFound), - Some(a) => a, + let query = ImageQuery { + album: Some(album_name.to_string()), + tags: tags.iter().map(|s| s.to_string()).collect(), + order: ImageSort::Random, + limit: 1, }; - let images: Vec = if tags.is_empty() { - album.images - } else { - album - .images - .iter() - .filter(|img| { - for tag in &tags { - if img.tags.contains(&tag.to_lowercase()) { - return true; - } - } - - false - }) - .cloned() - .collect() - }; - - Ok(images.choose(&mut rng).cloned()) + Ok(self.query_image(query).await?.first().cloned()) } - pub fn add_album(db: &Database, album_name: &str) -> Result { - db.insert(Album { - id: None, + #[allow(dead_code)] + pub async fn add_album(&self, album_name: &str) -> Result { + let create_album = CreateAlbum { album_name: album_name.to_string(), - images: vec![], - aliases: vec![], - }) - } -} - -impl JdbModel for Album { - fn id(&self) -> Option { - self.id - } - - fn set_id(&mut self, id: u64) { - self.id = Some(id) - } - - fn tree() -> String { - "img_album".to_string() + }; + + Ok(self + .api_client + .post(self.base_url.join("api/album/create").unwrap()) + .header("token", &self.token) + .json(&create_album) + .send() + .await? + .json() + .await?) + } + + pub async fn add_image( + &self, + album_name: &str, + tags: Vec, + file_name: &str, + img_data: Vec, + ) -> Result { + let add_image = AddImage { + album: AlbumQuery { + album_name: Some(album_name.to_string()), + }, + tags, + }; + + let file_name = file_name.to_string(); + + let form = Form::new() + .part( + "metadata", + Part::text(serde_json::to_string(&add_image).unwrap()), + ) + .part("img_data", Part::bytes(img_data).file_name(file_name)); + + let resp = self + .api_client + .post(self.base_url.join("api/image/").unwrap()) + .header("token", &self.token) + .multipart(form) + .send() + .await? + .json() + .await?; + + Ok(resp) } } diff --git a/src/config.rs b/src/config.rs index b29d74a..85ecbe1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use crate::album_manager::AlbumManager; use crate::error::Error; use crate::migrations::do_migration; use config::{Config, File}; @@ -20,6 +21,12 @@ pub struct Args { pub cfg_path: PathBuf, } +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PicOxConfig { + api_base_url: Url, + token: String, +} + #[derive(Debug, Deserialize, Serialize, Clone)] pub struct BotConfig { pub bot_token: String, @@ -35,6 +42,7 @@ pub struct BotConfig { pub announcement_channel: ChannelId, pub toys: Vec, pub effect_role_duration: i64, + pub picox: PicOxConfig, } impl BotConfig { @@ -69,6 +77,7 @@ pub struct GlobalData { pub cfg: BotConfig, pub bot_state: BotState, pub db: Database, + pub picox: AlbumManager, } impl GlobalData { @@ -81,7 +90,8 @@ impl GlobalData { args, bot_state: BotState::new().await?, db, - cfg, + cfg: cfg.clone(), + picox: AlbumManager::new(cfg.picox.api_base_url, &cfg.picox.token), }) } diff --git a/src/discord/album.rs b/src/discord/album.rs index 3b25609..a758f60 100644 --- a/src/discord/album.rs +++ b/src/discord/album.rs @@ -1,14 +1,12 @@ -use crate::album_manager::{Album, Image}; -use crate::discord::admin::is_admin; +use crate::album_manager::AlbumQuery; use crate::error::Error; use crate::{command, group, GlobalData}; -use j_db::model::JdbModel; use serenity::client::Context; use serenity::framework::standard::{Args, CommandResult}; use serenity::model::channel::Message; #[group] -#[commands(add_image, remove_album, list_albums, import_from_file)] +#[commands(add_image, list_albums)] pub struct AlbumCmd; #[command] @@ -24,127 +22,23 @@ async fn add_image(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul let global_data = data.get_mut::().unwrap(); - let album = Album::find_album_by_name_or_alias(&global_data.db, &album_name).unwrap(); - - let mut album = if let Some(album) = album { - album - } else { - Album::add_album(&global_data.db, &album_name).unwrap() - }; - for attachment in &msg.attachments { let data = attachment.download().await.unwrap(); - let img = Image::new( - &data, - &attachment.filename, - global_data.cfg.img_path.clone(), - tags.clone(), - ) - .await; - album.images.push(img); - } - global_data.db.insert(album).unwrap(); - - let plural = if msg.attachments.len() > 1 { "s" } else { "" }; - - msg.reply( - &ctx.http, - format!("Image{} added to {}!", plural, album_name), - ) - .await?; - - Ok(()) -} - -#[command] -#[min_args(1)] -#[description("Bulk add images")] -#[usage("")] -async fn import_from_file(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { - let album_name = args.parse::()?; - args.advance(); - let album_path = args.parse::()?; - let album_path = album_path.replace('"', ""); - - let mut data = ctx.data.write().await; - - let global_data = data.get_mut::().unwrap(); - - if !is_admin(&msg.author.id, &global_data.cfg) { - return Ok(()); - } - - let album = Album::find_album_by_name_or_alias(&global_data.db, &album_name).unwrap(); - - let mut album = if let Some(album) = album { - album - } else { - Album::add_album(&global_data.db, &album_name).unwrap() - }; - - let mut dir = tokio::fs::read_dir(album_path).await.unwrap(); - - while let Some(entry) = dir.next_entry().await? { - let data = tokio::fs::read(entry.path()).await?; - let img = Image::new( - &data, - entry.path().file_name().unwrap().to_str().unwrap(), - global_data.cfg.img_path.clone(), - vec![], - ) - .await; - album.images.push(img); - } - - global_data.db.insert(album).unwrap(); - - let plural = if msg.attachments.len() > 1 { "s" } else { "" }; - - msg.reply( - &ctx.http, - format!("Image{} added to {}!", plural, album_name), - ) - .await?; - - Ok(()) -} - -#[command] -#[max_args(1)] -#[description("Remove an imgur album command.")] -#[usage("")] -async fn remove_album(ctx: &Context, msg: &Message, args: Args) -> CommandResult { - let album_name = args.parse::()?; - - let mut data = ctx.data.write().await; - - let global_data = data.get_mut::().unwrap(); - - let album = Album::find_album_by_name_or_alias(&global_data.db, &album_name).unwrap(); - - match album { - None => { - msg.reply( - &ctx.http, - "I already got rid of that one, or I never had it. Who knows!", - ) + global_data + .picox + .add_image(&album_name, tags.clone(), &attachment.filename, data) .await?; - } - Some(album) => { - for img in &album.images { - tokio::fs::remove_file(img.full_path(global_data.cfg.img_path.clone())) - .await - .unwrap(); - } - - global_data.db.remove::(album.id().unwrap())?; - - msg.reply(&ctx.http, format!("{} album removed!", album_name)) - .await?; - } } + let plural = if msg.attachments.len() > 1 { "s" } else { "" }; + + msg.reply( + &ctx.http, + format!("Image{} added to {}!", plural, album_name), + ) + .await?; + Ok(()) } @@ -156,14 +50,15 @@ async fn list_albums(ctx: &Context, msg: &Message, _args: Args) -> CommandResult let global_data = data.get::().unwrap(); - let album_names: Vec = global_data - .db - .filter(|_, _: &Album| true)? - .map(|album| album.album_name) - .collect(); + let albums = global_data + .picox + .query_album(AlbumQuery { album_name: None }) + .await?; + + let album_names: Vec = albums.iter().map(|a| a.album_name.clone()).collect(); if album_names.is_empty() { - msg.reply(&ctx.http, "There are no albums configured!") + msg.reply(&ctx.http, "There are no albums in picox!") .await?; } else { msg.reply( @@ -185,19 +80,13 @@ pub async fn parse_album( let data = ctx.data.read().await; let global_data = data.get::().unwrap(); - let img = match Album::get_random_image(&global_data.db, album_name, tags) { + let img = match global_data.picox.get_random_image(album_name, tags).await { Ok(img) => img, - Err(err) => { - return match err { - Error::NoAlbumFound => Ok(false), - _ => Err(err), - } - } + Err(_) => return Ok(false), }; if let Some(img) = img { - msg.reply(&ctx.http, img.link(&global_data.cfg.base_url)) - .await?; + msg.reply(&ctx.http, img.link).await?; } else { msg.reply(&ctx.http, "No image found :(").await?; } diff --git a/src/discord/joke.rs b/src/discord/joke.rs index afa0957..99a7450 100644 --- a/src/discord/joke.rs +++ b/src/discord/joke.rs @@ -1,10 +1,8 @@ -use crate::album_manager::Album; +use crate::album_manager::{Album, AlbumQuery, ImageQuery, ImageSort}; use crate::error::Error; use crate::models::insult_compliment::{RandomResponseTemplate, ResponseType}; use crate::models::random::RandomConfig; use crate::{command, group, GlobalData, BAD_APPLE}; -use rand::prelude::SliceRandom; -use rand::thread_rng; use reqwest::Client; use serde::{Deserialize, Serialize}; use serenity::builder::EditMessage; @@ -53,18 +51,28 @@ struct RandomCtx { } impl RandomCtx { - pub fn new(user_name: &str, global_data: &GlobalData) -> Result { + pub async fn new(user_name: &str, global_data: &GlobalData) -> Result { let mut random_image: HashMap = HashMap::new(); - let albums: Vec = global_data.db.filter(|_, _album: &Album| true)?.collect(); + let albums: Vec = global_data + .picox + .query_album(AlbumQuery { album_name: None }) + .await?; for album in albums { - let image = album.images.choose(&mut thread_rng()); + let images = global_data + .picox + .query_image(ImageQuery { + album: Some(album.album_name.clone()), + tags: vec![], + order: ImageSort::Random, + limit: 1, + }) + .await?; + + let image = images.first(); if let Some(image) = image { - random_image.insert( - album.album_name.clone(), - image.link(&global_data.cfg.base_url).to_string(), - ); + random_image.insert(album.album_name.clone(), image.link.to_string()); } } @@ -75,12 +83,12 @@ impl RandomCtx { } } -pub fn render_random( +pub async fn render_random( author_name: &str, global_data: &GlobalData, template: &str, ) -> Result { - let random_ctx = RandomCtx::new(author_name, global_data)?; + let random_ctx = RandomCtx::new(author_name, global_data).await?; Ok(tera::Tera::one_off( template, @@ -118,7 +126,8 @@ pub async fn random(ctx: &Context, msg: &Message, random_name: &str) -> CommandR guild_member.display_name(), global_data, response_template_str, - )?; + ) + .await?; msg.reply(&ctx.http, reply).await?; @@ -144,7 +153,7 @@ pub async fn add_random(ctx: &Context, msg: &Message, mut args: Args) -> Command args.advance(); let random_response = args.rest(); - if let Err(err) = render_random(&msg.author.name, global_data, random_response) { + if let Err(err) = render_random(&msg.author.name, global_data, random_response).await { msg.reply( &ctx.http, format!("Template failed test render, try again: {}", err), diff --git a/src/discord/motivate.rs b/src/discord/motivate.rs index c950067..3e0cca2 100644 --- a/src/discord/motivate.rs +++ b/src/discord/motivate.rs @@ -1,6 +1,8 @@ +use crate::album_manager::AlbumQuery; use crate::models::motivation::{Motivation, MotivationConfig}; use crate::{command, group, GlobalData}; use magick_rust::{DrawingWand, MagickWand, PixelWand}; +use reqwest::Client; use serenity::builder::{CreateAttachment, CreateMessage}; use serenity::client::Context; use serenity::framework::standard::{Args, CommandError, CommandResult}; @@ -17,7 +19,15 @@ use std::borrow::Cow; pub struct Motivate; pub async fn create_motivation_image(motivation: Motivation) -> Result, CommandError> { - let motivation_image_blob = tokio::fs::read(motivation.image_path).await?; + let client = Client::new(); + + let motivation_image_blob = client + .get(motivation.image.link) + .send() + .await? + .bytes() + .await? + .to_vec(); let text = format!("{} {}", motivation.action, motivation.goal); @@ -72,7 +82,7 @@ async fn motivation(ctx: &Context, msg: &Message, args: Args) -> CommandResult { let motivation = MotivationConfig::generate_motivation( &global_data.db, - &global_data.cfg.img_path, + &global_data.picox, "white", album_name, ) @@ -102,8 +112,21 @@ async fn motivation_add_album(ctx: &Context, msg: &Message, args: Args) -> Comma let global_data = data.get::().unwrap(); let album = args.parse::()?; + let albums = global_data + .picox + .query_album(AlbumQuery { + album_name: Some(album), + }) + .await?; - MotivationConfig::add_album(&global_data.db, &album)?; + let album = if let Some(album) = albums.first().cloned() { + album + } else { + msg.reply(&ctx.http, "Fake album tbh, try again!").await?; + return Ok(()); + }; + + MotivationConfig::add_album(&global_data.db, album.id)?; msg.reply(&ctx.http, "Done ;)").await?; diff --git a/src/discord/shop.rs b/src/discord/shop.rs index 2653209..f6ade45 100644 --- a/src/discord/shop.rs +++ b/src/discord/shop.rs @@ -466,7 +466,7 @@ pub async fn restock_shop(ctx: &Context, global_data: &GlobalData) -> Result<(), let nft_motivation = MotivationConfig::generate_motivation( &global_data.db, - &global_data.cfg.img_path, + &global_data.picox, "gold", None, ) diff --git a/src/error.rs b/src/error.rs index a472544..49c7221 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,7 @@ pub enum Error { NoAlbumFound, UserError(user::UserError), DbError(j_db::error::JDbError), + ReqwestError(reqwest::Error), } impl StdError for Error {} @@ -46,6 +47,12 @@ impl From for Error { } } +impl From for Error { + fn from(err: reqwest::Error) -> Self { + Self::ReqwestError(err) + } +} + impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { @@ -55,6 +62,7 @@ impl Display for Error { Error::NoAlbumFound => write!(f, "No album found"), Error::UserError(e) => write!(f, "User error: {}", e), Error::DbError(e) => write!(f, "DB error: {}", e), + Error::ReqwestError(e) => write!(f, "Reqwest Error: {}", e), } } } diff --git a/src/models/motivation.rs b/src/models/motivation.rs index d39925d..2efa29d 100644 --- a/src/models/motivation.rs +++ b/src/models/motivation.rs @@ -1,4 +1,4 @@ -use crate::album_manager::Album; +use crate::album_manager::{AlbumManager, AlbumQuery, Image}; use crate::error::Error; use j_db::database::Database; use j_db::error::JDbError; @@ -6,7 +6,7 @@ use j_db::model::JdbModel; use rand::prelude::{IteratorRandom, SliceRandom}; use rand::thread_rng; use serde::{Deserialize, Serialize}; -use std::path::{Path, PathBuf}; +use std::fmt::Debug; #[derive(Debug, Deserialize, Serialize, Clone)] pub struct MotivationConfig { @@ -47,12 +47,9 @@ impl MotivationConfig { })) } - pub fn add_album(db: &Database, album: &str) -> Result<(), Error> { + pub fn add_album(db: &Database, id: u64) -> Result<(), Error> { let mut motivation = Self::get_motivation_config(db)?; - let album = Album::find_album_by_name_or_alias(db, album) - .unwrap() - .unwrap(); - motivation.album.push(album.id().unwrap()); + motivation.album.push(id); db.insert(motivation)?; @@ -79,7 +76,7 @@ impl MotivationConfig { pub async fn generate_motivation( db: &Database, - base_path: &Path, + picox: &AlbumManager, border_color: &str, album_name: Option, ) -> Result { @@ -88,16 +85,21 @@ impl MotivationConfig { let mut images = Vec::new(); if let Some(album_name) = album_name { - let album = Album::find_album_by_name_or_alias(db, &album_name)?; + let query = AlbumQuery { + album_name: Some(album_name), + }; + let albums = picox.query_album(query).await?; - if let Some(mut album) = album { - images.append(&mut album.images) + let album = albums.first(); + + if let Some(album) = album { + images.append(&mut album.images.clone()) } else { return Err(Error::from(JDbError::NotFound)); } } else { for album in motivation.album { - let album = db.get::(album); + let album = picox.get_album_by_id(album).await; if let Ok(album) = album { let mut album_images = album.images.clone(); @@ -114,8 +116,10 @@ impl MotivationConfig { let goal = motivation.goal.iter().choose(&mut thread_rng()).unwrap(); + let image = picox.get_image_by_id(*image).await.unwrap(); + Ok(Motivation { - image_path: image.full_path(base_path.to_path_buf()), + image, action: action.to_string(), goal: goal.to_string(), border_color: border_color.to_string(), @@ -125,7 +129,7 @@ impl MotivationConfig { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct Motivation { - pub image_path: PathBuf, + pub image: Image, pub action: String, pub goal: String, pub border_color: String,