Fix clippy lint errors
Some checks failed
Push Workflows / test (push) Successful in 1m33s
Push Workflows / docs (push) Successful in 1m45s
Push Workflows / clippy (push) Failing after 2m25s
Push Workflows / build (push) Successful in 4m0s
Push Workflows / leptos-test (push) Successful in 6m33s
Push Workflows / docker-build (push) Successful in 7m44s
Push Workflows / nix-build (push) Successful in 19m55s

This commit is contained in:
2025-02-05 22:56:11 -05:00
parent 7a0ae4c028
commit 0f48dfeada
30 changed files with 146 additions and 151 deletions

View File

@ -29,7 +29,7 @@ pub async fn add_album(album_title: String, release_date: Option<String>, image_
let parsed_release_date = match release_date {
Some(date) => {
match NaiveDate::parse_from_str(&date.trim(), "%Y-%m-%d") {
match NaiveDate::parse_from_str(date.trim(), "%Y-%m-%d") {
Ok(parsed_date) => Some(parsed_date),
Err(_e) => return Err(ServerFnError::<NoCustomError>::ServerError("Invalid release date".to_string()))
}
@ -37,16 +37,7 @@ pub async fn add_album(album_title: String, release_date: Option<String>, image_
None => None
};
let image_path_arg = match image_path {
Some(image_path) => {
if image_path.is_empty() {
None
} else {
Some(image_path)
}
},
None => None
};
let image_path_arg = image_path.filter(|image_path| !image_path.is_empty());
let new_album = Album {
id: None,

View File

@ -92,7 +92,7 @@ pub async fn top_songs_by_artist(artist_id: i32, limit: Option<i64>) -> Result<V
};
let song_play_counts: HashMap<i32, i64> = song_play_counts.into_iter().collect();
let top_song_ids: Vec<i32> = song_play_counts.iter().map(|(song_id, _)| *song_id).collect();
let top_song_ids: Vec<i32> = song_play_counts.keys().copied().collect();
let top_songs: Vec<(Song, Option<Album>, Option<Artist>, Option<(i32, i32)>, Option<(i32, i32)>)>
= songs::table
@ -131,20 +131,20 @@ pub async fn top_songs_by_artist(artist_id: i32, limit: Option<i64>) -> Result<V
};
let image_path = song.image_path.unwrap_or(
album.as_ref().map(|album| album.image_path.clone()).flatten()
album.as_ref().and_then(|album| album.image_path.clone())
.unwrap_or("/assets/images/placeholders/MusicPlaceholder.svg".to_string()));
let songdata = frontend::Song {
id: song_id,
title: song.title,
artists: artist.map(|artist| vec![artist]).unwrap_or_default(),
album: album,
album,
track: song.track,
duration: song.duration,
release_date: song.release_date,
song_path: song.storage_path,
image_path: image_path,
like_dislike: like_dislike,
image_path,
like_dislike,
added_date: song.added_date.unwrap(),
};
@ -155,7 +155,7 @@ pub async fn top_songs_by_artist(artist_id: i32, limit: Option<i64>) -> Result<V
}
}
let mut top_songs: Vec<(frontend::Song, i64)> = top_songs_map.into_iter().map(|(_, v)| v).collect();
let mut top_songs: Vec<(frontend::Song, i64)> = top_songs_map.into_values().collect();
top_songs.sort_by(|(_, plays1), (_, plays2)| plays2.cmp(plays1));
Ok(top_songs)
}
@ -205,7 +205,7 @@ pub async fn albums_by_artist(artist_id: i32, limit: Option<i64>) -> Result<Vec<
}
}
let mut albums: Vec<frontend::Album> = albums_map.into_iter().map(|(_, v)| v).collect();
let mut albums: Vec<frontend::Album> = albums_map.into_values().collect();
albums.sort_by(|a1, a2| a2.release_date.cmp(&a1.release_date));
Ok(albums)
}

View File

@ -114,9 +114,9 @@ pub async fn check_auth() -> Result<bool, ServerFnError> {
/// use libretunes::api::auth::require_auth;
/// #[server(endpoint = "protected_route")]
/// pub async fn protected_route() -> Result<(), ServerFnError> {
/// require_auth().await?;
/// // Continue with protected route
/// Ok(())
/// require_auth().await?;
/// // Continue with protected route
/// Ok(())
/// }
/// ```
#[cfg(feature = "ssr")]
@ -125,7 +125,7 @@ pub async fn require_auth() -> Result<(), ServerFnError> {
if logged_in {
Ok(())
} else {
Err(ServerFnError::<NoCustomError>::ServerError(format!("Unauthorized")))
Err(ServerFnError::<NoCustomError>::ServerError("Unauthorized".to_string()))
}
})
}
@ -139,10 +139,10 @@ pub async fn require_auth() -> Result<(), ServerFnError> {
/// use libretunes::api::auth::get_user;
/// #[server(endpoint = "user_route")]
/// pub async fn user_route() -> Result<(), ServerFnError> {
/// let user = get_user().await?;
/// println!("Logged in as: {}", user.username);
/// // Do something with the user
/// Ok(())
/// let user = get_user().await?;
/// println!("Logged in as: {}", user.username);
/// // Do something with the user
/// Ok(())
/// }
/// ```
#[cfg(feature = "ssr")]
@ -184,9 +184,9 @@ pub async fn check_admin() -> Result<bool, ServerFnError> {
/// use libretunes::api::auth::require_admin;
/// #[server(endpoint = "protected_admin_route")]
/// pub async fn protected_admin_route() -> Result<(), ServerFnError> {
/// require_admin().await?;
/// // Continue with protected route
/// Ok(())
/// require_admin().await?;
/// // Continue with protected route
/// Ok(())
/// }
/// ```
#[cfg(feature = "ssr")]
@ -195,7 +195,7 @@ pub async fn require_admin() -> Result<(), ServerFnError> {
if is_admin {
Ok(())
} else {
Err(ServerFnError::<NoCustomError>::ServerError(format!("Unauthorized")))
Err(ServerFnError::<NoCustomError>::ServerError("Unauthorized".to_string()))
}
})
}

View File

@ -126,20 +126,20 @@ pub async fn recent_songs(for_user_id: i32, limit: Option<i64>) -> Result<Vec<(N
};
let image_path = song.image_path.unwrap_or(
album.as_ref().map(|album| album.image_path.clone()).flatten()
album.as_ref().and_then(|album| album.image_path.clone())
.unwrap_or("/assets/images/placeholders/MusicPlaceholder.svg".to_string()));
let songdata = frontend::Song {
id: song_id,
title: song.title,
artists: artist.map(|artist| vec![artist]).unwrap_or_default(),
album: album,
album,
track: song.track,
duration: song.duration,
release_date: song.release_date,
song_path: song.storage_path,
image_path: image_path,
like_dislike: like_dislike,
image_path,
like_dislike,
added_date: song.added_date.unwrap(),
};
@ -186,7 +186,7 @@ pub async fn top_songs(for_user_id: i32, start_date: NaiveDateTime, end_date: Na
};
let history_counts: HashMap<i32, i64> = history_counts.into_iter().collect();
let history_song_ids = history_counts.iter().map(|(song_id, _)| *song_id).collect::<Vec<i32>>();
let history_song_ids = history_counts.keys().copied().collect::<Vec<i32>>();
// Get the song data for the songs listened to in the date range
let history_songs: Vec<(Song, Option<Album>, Option<Artist>, Option<(i32, i32)>, Option<(i32, i32)>)>
@ -227,20 +227,20 @@ pub async fn top_songs(for_user_id: i32, start_date: NaiveDateTime, end_date: Na
};
let image_path = song.image_path.unwrap_or(
album.as_ref().map(|album| album.image_path.clone()).flatten()
album.as_ref().and_then(|album| album.image_path.clone())
.unwrap_or("/assets/images/placeholders/MusicPlaceholder.svg".to_string()));
let songdata = frontend::Song {
id: song_id,
title: song.title,
artists: artist.map(|artist| vec![artist]).unwrap_or_default(),
album: album,
album,
track: song.track,
duration: song.duration,
release_date: song.release_date,
song_path: song.storage_path,
image_path: image_path,
like_dislike: like_dislike,
image_path,
like_dislike,
added_date: song.added_date.unwrap(),
};

View File

@ -84,8 +84,7 @@ pub async fn get_song_by_id(song_id: i32) -> Result<Option<frontend::Song>, Serv
.load(db_con)?;
let song = song_parts.first().cloned();
let artists = song_parts.into_iter().map(|(_, _, artist, _, _)| artist)
.filter_map(|artist| artist).collect::<Vec<_>>();
let artists = song_parts.into_iter().filter_map(|(_, _, artist, _, _)| artist).collect::<Vec<_>>();
match song {
Some((song, album, _artist, like, dislike)) => {
@ -99,13 +98,13 @@ pub async fn get_song_by_id(song_id: i32) -> Result<Option<frontend::Song>, Serv
Ok(Some(frontend::Song {
id: song.id.unwrap(),
title: song.title.clone(),
artists: artists,
album: album.clone().map(|album| album.into()),
artists,
album: album.clone(),
track: song.track,
duration: song.duration,
release_date: song.release_date,
song_path: song.storage_path.clone(),
image_path: image_path,
image_path,
like_dislike: Some((like.is_some(), dislike.is_some())),
added_date: song.added_date.unwrap(),
}))

View File

@ -108,13 +108,13 @@ async fn validate_track_number(track_number: Field<'static>) -> Result<Option<i3
if let Ok(track_number) = track_number.parse::<i32>() {
if track_number < 0 {
return Err(ServerFnError::<NoCustomError>::
ServerError("Track number must be positive or 0".to_string()));
Err(ServerFnError::<NoCustomError>::
ServerError("Track number must be positive or 0".to_string()))
} else {
Ok(Some(track_number))
}
} else {
return Err(ServerFnError::<NoCustomError>::ServerError("Error parsing track number".to_string()));
Err(ServerFnError::<NoCustomError>::ServerError("Error parsing track number".to_string()))
}
},
Err(e) => Err(ServerFnError::<NoCustomError>::ServerError(format!("Error reading track number: {}", e)))?,
@ -131,7 +131,7 @@ async fn validate_release_date(release_date: Field<'static>) -> Result<Option<Na
return Ok(None);
}
let release_date = NaiveDate::parse_from_str(&release_date.trim(), "%Y-%m-%d");
let release_date = NaiveDate::parse_from_str(release_date.trim(), "%Y-%m-%d");
match release_date {
Ok(release_date) => Ok(Some(release_date)),
@ -192,10 +192,11 @@ pub async fn upload(data: MultipartData) -> Result<(), ServerFnError> {
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(upload_path.clone())?;
while let Some(chunk) = field.chunk().await? {
file.write(&chunk)?;
file.write_all(&chunk)?;
}
file.flush()?;

View File

@ -42,7 +42,7 @@ pub fn AddAlbum(open: RwSignal<bool>) -> impl IntoView {
release_date.set("".to_string());
image_path.set("".to_string());
}
})
});
};
view! {

View File

@ -34,7 +34,7 @@ pub fn AddArtist(open: RwSignal<bool>) -> impl IntoView {
log!("Added artist: {:?}", artist);
artist_name.set("".to_string());
}
})
});
};
view! {

View File

@ -26,9 +26,7 @@ pub fn Profile() -> impl IntoView {
let user_profile_picture = move || {
user.get().and_then(|user| {
if let Some(user) = user {
if user.id.is_none() {
return None;
}
user.id?;
Some(format!("/assets/images/profile/{}.webp", user.id.unwrap()))
} else {
None

View File

@ -96,13 +96,11 @@ pub fn set_playing(play: bool) {
status.playing = true;
log!("Successfully played audio");
}
} else if let Err(e) = audio.pause() {
error!("Unable to pause audio: {:?}", e);
} else {
if let Err(e) = audio.pause() {
error!("Unable to pause audio: {:?}", e);
} else {
status.playing = false;
log!("Successfully paused audio");
}
status.playing = false;
log!("Successfully paused audio");
}
} else {
error!("Unable to play/pause audio: Audio element not available");
@ -239,7 +237,7 @@ fn MediaInfo() -> impl IntoView {
let artist = Signal::derive(move || {
status.with(|status| {
status.queue.front().map_or("".into(), |song| format!("{}", Artist::display_list(&song.artists)))
status.queue.front().map_or("".into(), |song| Artist::display_list(&song.artists).to_string())
})
});
@ -324,7 +322,6 @@ fn LikeDislike() -> impl IntoView {
},
_ => {
log!("Unable to like song: No song in queue");
return;
}
}
});
@ -364,7 +361,6 @@ fn LikeDislike() -> impl IntoView {
},
_ => {
log!("Unable to dislike song: No song in queue");
return;
}
}
});
@ -532,13 +528,13 @@ pub fn PlayBar() -> impl IntoView {
if let Some(src) = src {
GlobalState::play_status().with_untracked(|status| {
if let Some(audio) = status.get_audio() {
audio.set_src(&src);
audio.set_src(src);
} else {
error!("Unable to set audio source: Audio element not available");
}
});
}
})
});
});
// Track the last song that was added to the history to prevent duplicates

View File

@ -158,7 +158,15 @@ pub fn SongArtists(artists: Vec<Artist>) -> impl IntoView {
Either::Right(view! { <span>{artist.name.clone()}</span> })
}
}
{if i < num_artists - 2 { ", " } else if i == num_artists - 2 { " & " } else { "" }}
{
use std::cmp::Ordering;
match i.cmp(&(num_artists - 2)) {
Ordering::Less => ", ",
Ordering::Equal => " & ",
Ordering::Greater => "",
}
}
}
}).collect::<Vec<_>>()
}
@ -224,13 +232,10 @@ pub fn SongLikeDislike(
// If an error occurs, check the like/dislike status again to ensure consistency
let check_like_dislike = move || {
spawn_local(async move {
match get_like_dislike_song(song_id.get_untracked()).await {
Ok((like, dislike)) => {
liked.set(like);
disliked.set(dislike);
},
Err(_) => {}
}
if let Ok((like, dislike)) = get_like_dislike_song(song_id.get_untracked()).await {
liked.set(like);
disliked.set(dislike);
}
});
};

View File

@ -60,7 +60,7 @@ pub fn Upload(open: RwSignal<bool>) -> impl IntoView {
set_filtered_artists.update(|value| *value = artists);
}
})
});
};
// Create a filter function to handle filtering albums
// Allow users to search for albums by title, converts the album title to album id to be handed off to backend
@ -80,7 +80,7 @@ pub fn Upload(open: RwSignal<bool>) -> impl IntoView {
log!("Filtered albums: {:?}", albums);
set_filtered_albums.update(|value| *value = albums);
}
})
});
};
let handle_response = Arc::new(move |response: &Response| {
@ -116,12 +116,12 @@ pub fn Upload(open: RwSignal<bool>) -> impl IntoView {
<span>Artists</span>
</div>
<Show
when=move || {filtered_artists.get().len() > 0}
when=move || {!filtered_artists.get().is_empty()}
fallback=move || view! {}
>
<ul class="artist_results search-results">
{
move || filtered_artists.get().iter().enumerate().map(|(_index,filtered_artist)| view! {
move || filtered_artists.get().iter().map(|filtered_artist| view! {
<Artist artist=filtered_artist.clone() artists=artists set_artists=set_artists set_filtered=set_filtered_artists/>
}).collect::<Vec<_>>()
}
@ -134,12 +134,12 @@ pub fn Upload(open: RwSignal<bool>) -> impl IntoView {
<span>Album ID</span>
</div>
<Show
when=move || {filtered_albums.get().len() > 0}
when=move || {!filtered_albums.get().is_empty()}
fallback=move || view! {}
>
<ul class="album_results search-results">
{
move || filtered_albums.get().iter().enumerate().map(|(_index,filtered_album)| view! {
move || filtered_albums.get().iter().map(|filtered_album| view! {
<Album album=filtered_album.clone() _albums=albums set_albums=set_albums set_filtered=set_filtered_albums/>
}).collect::<Vec<_>>()
}
@ -190,12 +190,12 @@ pub fn Artist(artist: Artist, artists: ReadSignal<String>, set_artists: WriteSig
let mut ids: Vec<&str> = all_artirts.split(",").collect();
//If there is only one artist in the input, get their id equivalent and add it to the string
if ids.len() == 1 {
let value_str = match artist.id.clone() {
let value_str = match artist.id {
Some(v) => v.to_string(),
None => String::from("None"),
};
s.push_str(&value_str);
s.push_str(",");
s.push(',');
set_artists.update(|value| *value = s);
//If there are multiple artists in the input, pop the last artist by string off the vector,
//get their id equivalent, and add it to the string
@ -203,14 +203,14 @@ pub fn Artist(artist: Artist, artists: ReadSignal<String>, set_artists: WriteSig
ids.pop();
for id in ids {
s.push_str(id);
s.push_str(",");
s.push(',');
}
let value_str = match artist.id.clone() {
let value_str = match artist.id {
Some(v) => v.to_string(),
None => String::from("None"),
};
s.push_str(&value_str);
s.push_str(",");
s.push(',');
set_artists.update(|value| *value = s);
}
//Clear the search results
@ -227,7 +227,7 @@ pub fn Artist(artist: Artist, artists: ReadSignal<String>, set_artists: WriteSig
pub fn Album(album: Album, _albums: ReadSignal<String>, set_albums: WriteSignal<String>, set_filtered: WriteSignal<Vec<Album>>) -> impl IntoView {
//Converts album title to album id to upload a song
let add_album = move |_| {
let value_str = match album.id.clone() {
let value_str = match album.id {
Some(v) => v.to_string(),
None => String::from("None"),
};

View File

@ -12,7 +12,7 @@ pub enum AppError {
}
impl AppError {
pub fn status_code(&self) -> StatusCode {
pub const fn status_code(&self) -> StatusCode {
match self {
AppError::NotFound => StatusCode::NOT_FOUND,
}

View File

@ -42,7 +42,7 @@ async fn main() {
debug!("Connecting to Redis...");
let redis_url = std::env::var("REDIS_URL").expect("REDIS_URL must be set");
let redis_config = RedisConfig::from_url(&redis_url).expect(&format!("Unable to parse Redis URL: {}", redis_url));
let redis_config = RedisConfig::from_url(&redis_url).unwrap_or_else(|_| panic!("Unable to parse Redis URL: {}", redis_url));
let redis_pool = RedisPool::new(redis_config, None, None, None, 1).expect("Unable to create Redis pool");
redis_pool.connect();
redis_pool.wait_for_connect().await.expect("Unable to connect to Redis");
@ -72,7 +72,7 @@ async fn main() {
.fallback(file_and_error_handler)
.with_state(leptos_options);
let listener = tokio::net::TcpListener::bind(&addr).await.expect(&format!("Could not bind to {}", &addr));
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap_or_else(|_| panic!("Could not bind to {}", &addr));
info!("Listening on http://{}", &addr);

View File

@ -153,8 +153,8 @@ impl Album {
duration: song.duration,
release_date: song.release_date,
song_path: song.storage_path,
image_path: image_path,
like_dislike: like_dislike,
image_path,
like_dislike,
added_date: song.added_date.unwrap(),
};

View File

@ -26,7 +26,7 @@ impl Artist {
///
/// For one artist, displays [artist1]. For two artists, displays [artist1] & [artist2].
/// For three or more artists, displays [artist1], [artist2], & [artist3].
pub fn display_list(artists: &Vec<Artist>) -> String {
pub fn display_list(artists: &[Artist]) -> String {
let mut artist_list = String::new();
for (i, artist) in artists.iter().enumerate() {

View File

@ -14,8 +14,8 @@ cfg_if! {
// Model for a "User", used for querying the database
/// Various fields are wrapped in Options, because they are not always wanted for inserts/retrieval
/// Using deserialize_as makes Diesel use the specified type when deserializing from the database,
/// and then call .into() to convert it into the Option
/// Using `deserialize_as` makes Diesel use the specified type when deserializing from the database,
/// and then call `.into()` to convert it into the Option
#[cfg_attr(feature = "ssr", derive(Queryable, Selectable, Insertable))]
#[cfg_attr(feature = "ssr", diesel(table_name = crate::schema::users))]
#[cfg_attr(feature = "ssr", diesel(check_for_backend(diesel::pg::Pg)))]
@ -55,10 +55,10 @@ impl User {
/// # Returns
///
/// * `Result<Vec<HistoryEntry>, Box<dyn Error>>` -
/// A result indicating success with a vector of history entries, or an error
/// A result indicating success with a vector of history entries, or an error
///
#[cfg(feature = "ssr")]
pub fn get_history(self: &Self, limit: Option<i64>, conn: &mut PgPooledConn) ->
pub fn get_history(&self, limit: Option<i64>, conn: &mut PgPooledConn) ->
Result<Vec<HistoryEntry>, Box<dyn Error>> {
use crate::schema::song_history::dsl::*;
@ -94,10 +94,10 @@ impl User {
/// # Returns
///
/// * `Result<Vec<(SystemTime, Song)>, Box<dyn Error>>` -
/// A result indicating success with a vector of listen dates and songs, or an error
/// A result indicating success with a vector of listen dates and songs, or an error
///
#[cfg(feature = "ssr")]
pub fn get_history_songs(self: &Self, limit: Option<i64>, conn: &mut PgPooledConn) ->
pub fn get_history_songs(&self, limit: Option<i64>, conn: &mut PgPooledConn) ->
Result<Vec<(NaiveDateTime, Song)>, Box<dyn Error>> {
use crate::schema::songs::dsl::*;
use crate::schema::song_history::dsl::*;
@ -140,7 +140,7 @@ impl User {
/// * `Result<(), Box<dyn Error>>` - A result indicating success with an empty value, or an error
///
#[cfg(feature = "ssr")]
pub fn add_history(self: &Self, song_id: i32, conn: &mut PgPooledConn) -> Result<(), Box<dyn Error>> {
pub fn add_history(&self, song_id: i32, conn: &mut PgPooledConn) -> Result<(), Box<dyn Error>> {
use crate::schema::song_history;
let my_id = self.id.ok_or("Artist id must be present (Some) to add history")?;
@ -155,7 +155,7 @@ impl User {
/// Like or unlike a song for this user
/// If likeing a song, remove dislike if it exists
#[cfg(feature = "ssr")]
pub async fn set_like_song(self: &Self, song_id: i32, like: bool, conn: &mut PgPooledConn) ->
pub async fn set_like_song(&self, song_id: i32, like: bool, conn: &mut PgPooledConn) ->
Result<(), Box<dyn Error>> {
use log::*;
debug!("Setting like for song {} to {}", song_id, like);
@ -184,7 +184,7 @@ impl User {
/// Get the like status of a song for this user
#[cfg(feature = "ssr")]
pub async fn get_like_song(self: &Self, song_id: i32, conn: &mut PgPooledConn) -> Result<bool, Box<dyn Error>> {
pub async fn get_like_song(&self, song_id: i32, conn: &mut PgPooledConn) -> Result<bool, Box<dyn Error>> {
use crate::schema::song_likes;
let my_id = self.id.ok_or("User id must be present (Some) to get like status of a song")?;
@ -201,7 +201,7 @@ impl User {
/// Dislike or remove dislike from a song for this user
/// If disliking a song, remove like if it exists
#[cfg(feature = "ssr")]
pub async fn set_dislike_song(self: &Self, song_id: i32, dislike: bool, conn: &mut PgPooledConn) ->
pub async fn set_dislike_song(&self, song_id: i32, dislike: bool, conn: &mut PgPooledConn) ->
Result<(), Box<dyn Error>> {
use log::*;
debug!("Setting dislike for song {} to {}", song_id, dislike);
@ -231,7 +231,7 @@ impl User {
/// Get the dislike status of a song for this user
#[cfg(feature = "ssr")]
pub async fn get_dislike_song(self: &Self, song_id: i32, conn: &mut PgPooledConn) -> Result<bool, Box<dyn Error>> {
pub async fn get_dislike_song(&self, song_id: i32, conn: &mut PgPooledConn) -> Result<bool, Box<dyn Error>> {
use crate::schema::song_dislikes;
let my_id = self.id.ok_or("User id must be present (Some) to get dislike status of a song")?;

View File

@ -23,13 +23,13 @@ pub struct Album {
pub image_path: String,
}
impl Into<DashboardTile> for Album {
fn into(self) -> DashboardTile {
impl From<Album> for DashboardTile {
fn from(val: Album) -> Self {
DashboardTile {
image_path: self.image_path.into(),
title: self.title.into(),
link: format!("/album/{}", self.id).into(),
description: Some(format!("Album • {}", Artist::display_list(&self.artists)).into()),
image_path: val.image_path.into(),
title: val.title.into(),
link: format!("/album/{}", val.id).into(),
description: Some(format!("Album • {}", Artist::display_list(&val.artists)).into()),
}
}
}

View File

@ -15,12 +15,12 @@ pub struct Artist {
pub image_path: String,
}
impl Into<DashboardTile> for Artist {
fn into(self) -> DashboardTile {
impl From<Artist> for DashboardTile {
fn from(val: Artist) -> Self {
DashboardTile {
image_path: self.image_path.into(),
title: self.name.into(),
link: format!("/artist/{}", self.id).into(),
image_path: val.image_path.into(),
title: val.name.into(),
link: format!("/artist/{}", val.id).into(),
description: Some("Artist".into()),
}
}

View File

@ -5,7 +5,7 @@ use std::collections::VecDeque;
use crate::models::frontend;
/// Represents the global state of the audio player feature of LibreTunes
/// Represents the global state of the audio player feature of `LibreTunes`
pub struct PlayStatus {
/// Whether or not the audio player is currently playing
pub playing: bool,
@ -27,9 +27,9 @@ impl PlayStatus {
/// use leptos::prelude::*;
/// let status = libretunes::models::frontend::PlayStatus::default();
/// if let Some(audio) = status.audio_player {
/// if let Some(audio) = audio.get() {
/// let _ = audio.play();
/// }
/// if let Some(audio) = audio.get() {
/// let _ = audio.play();
/// }
/// }
/// ```
///
@ -37,7 +37,7 @@ impl PlayStatus {
/// ```
/// let status = libretunes::models::frontend::PlayStatus::default();
/// if let Some(audio) = status.get_audio() {
/// let _ = audio.play();
/// let _ = audio.play();
/// }
/// ```
pub fn get_audio(&self) -> Option<HtmlAudioElement> {
@ -52,7 +52,7 @@ impl PlayStatus {
}
impl Default for PlayStatus {
/// Creates a paused PlayStatus with no audio player, no progress update handle, and empty queue/history
/// Creates a paused `PlayStatus` with no audio player, no progress update handle, and empty queue/history
fn default() -> Self {
Self {
playing: false,

View File

@ -39,10 +39,10 @@ pub struct Song {
impl TryInto<backend::Song> for Song {
type Error = Box<dyn std::error::Error>;
/// Convert a SongData object into a Song object
/// Convert a `SongData` object into a Song object
///
/// The SongData/Song conversions are also not truly reversible,
/// due to the way the image_path data is handled.
/// due to the way the `image_path` data is handled.
fn try_into(self) -> Result<backend::Song, Self::Error> {
Ok(backend::Song {
id: Some(self.id),
@ -67,13 +67,13 @@ impl TryInto<backend::Song> for Song {
}
}
impl Into<DashboardTile> for Song {
fn into(self) -> DashboardTile {
impl From<Song> for DashboardTile {
fn from(val: Song) -> Self {
DashboardTile {
image_path: self.image_path.into(),
title: self.title.into(),
link: format!("/song/{}", self.id).into(),
description: Some(format!("Song • {}", Artist::display_list(&self.artists)).into()),
image_path: val.image_path.into(),
title: val.title.into(),
link: format!("/song/{}", val.id).into(),
description: Some(format!("Song • {}", Artist::display_list(&val.artists)).into()),
}
}
}

View File

@ -28,7 +28,7 @@ pub fn AlbumPage() -> impl IntoView {
|value| async move {
match value {
Ok(v) => {get_songs(v).await},
Err(e) => {Err(ServerFnError::Request(format!("Error getting song data: {}", e).into()))},
Err(e) => {Err(ServerFnError::Request(format!("Error getting song data: {}", e)))},
}
},
);
@ -38,7 +38,7 @@ pub fn AlbumPage() -> impl IntoView {
|value| async move {
match value {
Ok(v) => {get_album(v).await},
Err(e) => {Err(ServerFnError::Request(format!("Error getting song data: {}", e).into()))},
Err(e) => {Err(ServerFnError::Request(format!("Error getting song data: {}", e)))},
}
},
);

View File

@ -152,9 +152,7 @@ fn AlbumsByArtist(#[prop(into)] artist_id: Signal<i32>) -> impl IntoView {
let albums = albums_by_artist(artist_id, None).await;
albums.map(|albums| {
albums.into_iter().map(|album| {
album
}).collect::<Vec<_>>()
albums.into_iter().collect::<Vec<_>>()
})
});

View File

@ -96,7 +96,7 @@ pub fn Login() -> impl IntoView {
<span>Password</span>
<i></i>
<Show
when=move || {show_password() == false}
when=move || {!show_password()}
fallback=move || view!{ <button on:click=toggle_password class="login-password-visibility">
<Icon icon={icondata::AiEyeInvisibleFilled} />
</button> /> }

View File

@ -56,7 +56,7 @@ pub fn Signup() -> impl IntoView {
// Redirect to the login page
log!("Signed up successfully!");
leptos_router::hooks::use_navigate()("/", Default::default());
log!("Navigated to home page after signup")
log!("Navigated to home page after signup");
}
loading.set(false);
@ -102,7 +102,7 @@ pub fn Signup() -> impl IntoView {
<span>Password</span>
<i></i>
<Show
when=move || {show_password() == false}
when=move || {!show_password()}
fallback=move || view!{ <button on:click=toggle_password class="password-visibility"> <Icon icon={icondata::AiEyeInvisibleFilled} /></button> /> }
>
<button on:click=toggle_password class="password-visibility">

View File

@ -146,7 +146,7 @@ fn SongOverview(song: frontend::Song) -> impl IntoView {
#[component]
fn SongPlays(#[prop(into)] id: Signal<i32>) -> impl IntoView {
let plays = Resource::new(move || id.get(), move |id| songs::get_song_plays(id));
let plays = Resource::new(move || id.get(), songs::get_song_plays);
view! {
<Transition
@ -175,7 +175,7 @@ fn SongPlays(#[prop(into)] id: Signal<i32>) -> impl IntoView {
#[component]
fn MySongPlays(#[prop(into)] id: Signal<i32>) -> impl IntoView {
let plays = Resource::new(move || id.get(), move |id| songs::get_my_song_plays(id));
let plays = Resource::new(move || id.get(), songs::get_my_song_plays);
view! {
<Transition

View File

@ -28,10 +28,10 @@ lazy_static! {
/// Initialize the database pool
///
/// Uses DATABASE_URL environment variable to connect to the database if set,
/// Uses `DATABASE_URL` environment variable to connect to the database if set,
/// otherwise builds a connection string from other environment variables.
///
/// Will panic if either the DATABASE_URL or POSTGRES_HOST environment variables
/// Will panic if either the `DATABASE_URL` or `POSTGRES_HOST` environment variables
/// are not set, or if there is an error creating the pool.
///
/// # Returns
@ -48,14 +48,14 @@ fn init_db_pool() -> PgPool {
log_url.push_str(&user);
if let Ok(password) = env::var("POSTGRES_PASSWORD") {
url.push_str(":");
log_url.push_str(":");
url.push(':');
log_url.push(':');
url.push_str(&password);
log_url.push_str("********");
}
url.push_str("@");
log_url.push_str("@");
url.push('@');
log_url.push('@');
}
let host = env::var("POSTGRES_HOST").expect("DATABASE_URL or POSTGRES_HOST must be set");
@ -64,16 +64,16 @@ fn init_db_pool() -> PgPool {
log_url.push_str(&host);
if let Ok(port) = env::var("POSTGRES_PORT") {
url.push_str(":");
url.push(':');
url.push_str(&port);
log_url.push_str(":");
log_url.push(':');
log_url.push_str(&port);
}
if let Ok(dbname) = env::var("POSTGRES_DB") {
url.push_str("/");
url.push('/');
url.push_str(&dbname);
log_url.push_str("/");
log_url.push('/');
log_url.push_str(&dbname);
}

View File

@ -32,7 +32,7 @@ pub async fn get_static_file(uri: Uri, root: &str) -> Result<Response<Body>, (St
Some(res) => Ok(res.into_response()),
None => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong"),
"Something went wrong".to_string(),
)),
}
}
@ -59,7 +59,7 @@ pub async fn get_asset_file(filename: String, asset_type: AssetType) -> Result<R
Ok(uri) => get_static_file(uri, root.as_str()).await,
Err(_) => Err((
StatusCode::INTERNAL_SERVER_ERROR,
format!("Attempted to serve an invalid file"),
"Attempted to serve an invalid file".to_string(),
)),
}
}

View File

@ -13,7 +13,7 @@ use axum::extract::FromRequestParts;
const ALLOWED_PATHS: [&str; 5] = ["/login", "/signup", "/api/login", "/api/signup", "/favicon.ico"];
/**
* Middleware to require authentication for all paths except those in ALLOWED_PATHS
* Middleware to require authentication for all paths except those in `ALLOWED_PATHS`
*
* If a user is not authenticated, they will be redirected to the login page
*/

View File

@ -7,7 +7,7 @@ use crate::api::auth::get_logged_in_user;
/// Global front-end state
/// Contains anything frequently needed across multiple components
/// Behaves like a singleton, in that provide/expect_context will
/// Behaves like a singleton, in that `provide_context`/`expect_context` will
/// always return the same instance
#[derive(Clone)]
pub struct GlobalState {
@ -47,3 +47,10 @@ impl GlobalState {
expect_context::<Self>().play_status
}
}
impl Default for GlobalState {
fn default() -> Self {
Self::new()
}
}