based
Some checks failed
ci/woodpecker/push/deploy Pipeline failed

This commit is contained in:
JMARyA 2024-12-18 18:59:00 +01:00
parent 4e98df4498
commit 1dfb3d4964
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
21 changed files with 338 additions and 523 deletions

View file

@ -1,4 +1,4 @@
use crate::route::ToAPI;
use based::request::api::ToAPI;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::FromRow;

View file

@ -1,4 +1,4 @@
use crate::route::ToAPI;
use based::request::api::ToAPI;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::FromRow;

View file

@ -1,7 +1,7 @@
use based::{auth::User, get_pg};
use serde::{Deserialize, Serialize};
use sqlx::prelude::FromRow;
use crate::{get_pg, library::user::User};
/// Represents a user event in the database.
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Event {

View file

@ -1,16 +1,13 @@
use album::Album;
use artist::Artist;
use based::{get_pg, request::cache::RouteCache};
use serde_json::json;
use std::{
path::{Path, PathBuf},
str::FromStr,
};
use album::Album;
use artist::Artist;
use serde_json::json;
use track::Track;
use walkdir::WalkDir;
use crate::{cache::RouteCache, get_pg};
pub mod album;
pub mod artist;
pub mod event;
@ -18,7 +15,6 @@ pub mod metadata;
pub mod playlist;
pub mod search;
pub mod track;
pub mod user;
/// Checks if a file has a music file extension
fn is_music_file(path: &Path) -> bool {

View file

@ -1,8 +1,7 @@
use based::{auth::User, get_pg};
use serde::{Deserialize, Serialize};
use sqlx::FromRow;
use crate::{get_pg, library::user::User};
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Playlist {
// Unique identifier of the playlist

View file

@ -1,10 +1,8 @@
use super::{album::Album, artist::Artist, playlist::Playlist, track::Track};
use based::request::api::ToAPI;
use serde::Serialize;
use std::cmp::Ordering;
use crate::route::ToAPI;
use super::{album::Album, artist::Artist, playlist::Playlist, track::Track};
// Calculate a score for a given field based on its similarity to the search term and recency factor
fn calculate_score(field: &str, search_term: &str, date_added: Option<i64>) -> f64 {
// Exact match bonus: assign a high score if the field exactly matches the search term

View file

@ -1,15 +1,15 @@
use crate::library::album::Album;
use based::{
auth::User,
get_pg,
request::api::{to_uuid, ToAPI},
};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::prelude::FromRow;
use std::{io::Read, str::FromStr};
use crate::{
get_pg,
library::album::Album,
route::{to_uuid, ToAPI},
};
use super::{metadata::AudioMetadata, user::User};
use super::metadata::AudioMetadata;
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Track {

View file

@ -1,154 +0,0 @@
use crate::route::ToAPI;
use data_encoding::HEXUPPER;
use rand::RngCore;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::FromRow;
use crate::get_pg;
fn gen_token(token_length: usize) -> String {
let mut token_bytes = vec![0u8; token_length];
rand::thread_rng().fill_bytes(&mut token_bytes);
HEXUPPER.encode(&token_bytes)
}
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct User {
/// The username chosen by the user
pub username: String,
/// The hashed password for the user
pub password: String,
/// The role of the user
pub user_role: UserRole,
}
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::Type)]
#[sqlx(type_name = "user_role", rename_all = "lowercase")]
pub enum UserRole {
/// A regular user with limited permissions
Regular,
/// An admin user with full system privileges
Admin,
}
impl User {
/// Find a user by their username
pub async fn find(username: &str) -> Option<Self> {
sqlx::query_as("SELECT * FROM users WHERE username = $1")
.bind(username)
.fetch_optional(get_pg!())
.await
.unwrap()
}
/// Create a new user with the given details
///
/// Returns an Option containing the created user, or None if a user already exists with the same username
pub async fn create(username: &str, password: &str, role: UserRole) -> Option<Self> {
// Check if a user already exists with the same username
if Self::find(username).await.is_some() {
return None;
}
let u = Self {
username: username.to_string(),
password: bcrypt::hash(password, bcrypt::DEFAULT_COST).unwrap(),
user_role: role,
};
sqlx::query("INSERT INTO users (username, \"password\", user_role) VALUES ($1, $2, $3)")
.bind(&u.username)
.bind(&u.password)
.bind(&u.user_role)
.execute(get_pg!())
.await
.unwrap();
Some(u)
}
/// Login a user with the given username and password
pub async fn login(username: &str, password: &str) -> Option<(Session, UserRole)> {
let u = Self::find(username).await?;
if !u.verify_pw(password) {
return None;
}
Some((u.session().await, u.user_role))
}
/// Change the password of a User
///
/// Returns a Result indicating whether the password change was successful or not
pub async fn passwd(self, old: &str, new: &str) -> Result<(), ()> {
if self.verify_pw(old) {
sqlx::query("UPDATE users SET \"password\" = $1 WHERE username = $2;")
.bind(bcrypt::hash(new, bcrypt::DEFAULT_COST).unwrap())
.bind(&self.username)
.fetch_one(get_pg!())
.await
.unwrap();
return Ok(());
}
Err(())
}
/// Find all users in the system
pub async fn find_all() -> Vec<Self> {
sqlx::query_as("SELECT * FROM users")
.fetch_all(get_pg!())
.await
.unwrap()
}
/// Generate a new session token for the user
///
/// Returns a Session instance containing the generated token and associated user
pub async fn session(&self) -> Session {
sqlx::query_as(
"INSERT INTO user_session (token, \"user\") VALUES ($1, $2) RETURNING id, token, \"user\"",
)
.bind(gen_token(64))
.bind(&self.username)
.fetch_one(get_pg!())
.await
.unwrap()
}
/// Check if the user is an admin
pub const fn is_admin(&self) -> bool {
matches!(self.user_role, UserRole::Admin)
}
/// Verify that a provided password matches the hashed password for the user
///
/// Returns a boolean indicating whether the passwords match or not
pub fn verify_pw(&self, password: &str) -> bool {
bcrypt::verify(password, &self.password).unwrap()
}
}
impl ToAPI for User {
async fn api(&self) -> serde_json::Value {
json!({
"username": self.username,
"role": self.user_role
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
pub struct Session {
/// The unique ID of the session token
pub id: uuid::Uuid,
/// The generated session token
pub token: String,
/// The username associated with the session token
pub user: String,
}