Compare commits

..

10 Commits

Author SHA1 Message Date
phoenix 432078e3c2 tsk-83: Add None value for MusicTypes and CoverArtTypes (#87)
Closes #83

Reviewed-on: #87
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-28 17:05:13 +00:00
phoenix 0a27b8ccb1 filename generation fix (#82)
Reviewed-on: #82
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-24 17:21:07 +00:00
phoenix afc4ca21a2 tsk-76: Improve getting path of Song or CoverArt (#81)
Closes #76

Reviewed-on: #81
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-24 16:51:08 +00:00
phoenix 02b6157e0d tsk-79: Create function to generate CoverArt filename (#80)
Closes #79

Reviewed-on: #80
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-24 16:19:38 +00:00
phoenix 860d684e7b Merge pull request 'v0.8 Changes' (#75) from next-v0.8 into main
Reviewed-on: #75
2025-10-20 01:47:05 +00:00
phoenix 97783568e9 cargo update 2025-10-19 21:25:30 -04:00
phoenix 5a8118726b Version bump 2025-10-19 21:23:32 -04:00
phoenix 9dcf46ec0a Updated workflows 2025-10-19 21:08:08 -04:00
phoenix 44d08cdb1f tsk-71: Add token expiration checks (#78)
Closes #71

Reviewed-on: #78
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-19 02:18:29 +00:00
phoenix 51c8b5c7b3 tsk-73: Change data type of song from string to date (#77)
Closes #73

Reviewed-on: #77
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-10-19 01:45:35 +00:00
14 changed files with 185 additions and 122 deletions
+7 -5
View File
@@ -1,10 +1,9 @@
name: Release Tagging
on:
pull_request:
push:
branches:
- main
- next-v0.8
jobs:
release:
@@ -26,12 +25,15 @@ jobs:
run: |
VERSION=$(grep '^version = "' Cargo.toml | sed -E 's/version = "([^"]+)"/\1/')
PROJECT_COMMIT_HASH=$(git rev-parse HEAD | cut -c 1-10)
BRANCH_REF="${GITHUB_REF}"
BRANCH_REF="${{ gitea.ref }}"
BRANCH_NAME=$(echo "$BRANCH_REF" | cut -d '/' -f 3)
PROJECT_TAG_RELEASE="v$VERSION-$BRANCH_NAME-$PROJECT_COMMIT_HASH"
echo "::set-output name=project_tag_release::$PROJECT_TAG_RELEASE-111"
PROJECT_TAG_RELEASE="v$VERSION-$BRANCH_NAME-$PROJECT_COMMIT_HASH-111"
echo "::set-output name=project_tag_release::$PROJECT_TAG_RELEASE"
echo "Version: $VERSION"
echo "Hash: $PROJECT_COMMIT_HASH"
echo "Branh ref: $BRANCH_REF"
echo "Branch: $BRANCH_NAME"
echo "Tag Release: $PROJECT_TAG_RELEASE"
-3
View File
@@ -7,7 +7,6 @@ on:
pull_request:
branches:
- main
- next-v0.8
jobs:
check:
@@ -61,5 +60,3 @@ jobs:
with:
toolchain: 1.90.0
- run: cargo build
Generated
+22 -31
View File
@@ -31,9 +31,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.9.4"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bumpalo"
@@ -53,9 +53,9 @@ dependencies = [
[[package]]
name = "cfg-if"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "crc32fast"
@@ -131,14 +131,14 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "getrandom"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasi",
"wasip2",
]
[[package]]
@@ -149,7 +149,7 @@ checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]]
name = "icarus_models"
version = "0.7.1"
version = "0.8.4"
dependencies = [
"josekit",
"rand",
@@ -163,9 +163,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.11.4"
version = "2.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
dependencies = [
"equivalent",
"hashbrown",
@@ -254,9 +254,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "openssl"
version = "0.10.73"
version = "0.10.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654"
dependencies = [
"bitflags",
"cfg-if",
@@ -280,9 +280,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.109"
version = "0.9.110"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2"
dependencies = [
"cc",
"libc",
@@ -366,9 +366,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.12.1"
version = "1.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433"
checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
dependencies = [
"aho-corasick",
"memchr",
@@ -378,9 +378,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.12"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
@@ -389,9 +389,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "rustix"
@@ -476,9 +476,9 @@ checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "syn"
version = "2.0.106"
version = "2.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b"
dependencies = [
"proc-macro2",
"quote",
@@ -597,15 +597,6 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasi"
version = "0.14.7+wasi-0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
dependencies = [
"wasip2",
]
[[package]]
name = "wasip2"
version = "1.0.1+wasi-0.2.4"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "icarus_models"
version = "0.7.1"
version = "0.8.4"
edition = "2024"
rust-version = "1.90"
description = "models used for the icarus project"
+3 -2
View File
@@ -1,2 +1,3 @@
A library containing commonly used models and functions that is used throughout
icarus projects. This reduces the amount of duplicated code without a benefit.
A library containing commonly used structs, functions, enums, constants and other code
that is used throughout the icarus projects. Code from this library serves as the model
for other projects in the icarus project.
+6
View File
@@ -12,3 +12,9 @@ pub mod file_extensions {
pub const PNGEXTENSION: &str = ".png";
}
}
pub mod error {
pub const DIRECTORY_NOT_INITIALIZED: &str = "Directory has not been initialized";
pub const FILENAME_NOT_INITIALIZED: &str = "Filename has not bee initialized";
pub const LAST_CHARACTER_IN_DIRECTORY: &str = "Could not access last character of directory";
}
+57 -20
View File
@@ -1,8 +1,10 @@
use std::io::Write;
use serde::{Deserialize, Serialize};
use rand::Rng;
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
const FILENAME_LENGTH: i32 = 16;
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize, utoipa::ToSchema)]
pub struct CoverArt {
pub id: uuid::Uuid,
pub title: String,
@@ -15,11 +17,9 @@ pub struct CoverArt {
}
pub mod init {
use super::CoverArt;
/// Initializes the CoverArt with just the directory and filename
pub fn init_coverart_dir_and_filename(directory: &str, filename: &str) -> CoverArt {
CoverArt {
pub fn init_coverart_dir_and_filename(directory: &str, filename: &str) -> super::CoverArt {
super::CoverArt {
directory: String::from(directory),
filename: String::from(filename),
..Default::default()
@@ -65,30 +65,67 @@ impl CoverArt {
/// Gets the path of the CoverArt
pub fn get_path(&self) -> Result<String, std::io::Error> {
if self.directory.is_empty() {
return Err(std::io::Error::other("Directory has not been initialized"));
return Err(std::io::Error::other(
crate::constants::error::DIRECTORY_NOT_INITIALIZED,
));
} else if self.filename.is_empty() {
return Err(std::io::Error::other("Filename has not bee initialized"));
return Err(std::io::Error::other(
crate::constants::error::FILENAME_NOT_INITIALIZED,
));
}
let directory = &self.directory;
let last_index = directory.len() - 1;
if let Some(character) = directory.chars().nth(last_index) {
let buffer = if character != '/' {
directory.clone() + "/"
} else {
directory.clone()
};
Ok(buffer + &self.filename.clone())
} else {
Err(std::io::Error::other(
"Could not access last character of directory",
))
match crate::util::concatenate_path(directory, &self.filename, last_index) {
Ok(path) => Ok(path),
Err(err) => Err(err),
}
}
}
/// Generates filename for a CoverArt
pub fn generate_filename(
typ: crate::types::CoverArtTypes,
randomize: bool,
) -> Result<String, std::io::Error> {
let file_extension = match typ {
crate::types::CoverArtTypes::PngExtension => {
String::from(crate::constants::file_extensions::image::PNGEXTENSION)
}
crate::types::CoverArtTypes::JpegExtension => {
String::from(crate::constants::file_extensions::image::JPEGEXTENSION)
}
crate::types::CoverArtTypes::JpgExtension => {
String::from(crate::constants::file_extensions::image::JPGEXTENSION)
}
crate::types::CoverArtTypes::None => {
return Err(std::io::Error::other("Unsupported CoverArtTypes"));
}
};
let filename: String = if randomize {
let mut filename: String = String::from("coverart-");
let some_chars: String = String::from("abcdefghij0123456789");
let some_chars_length = some_chars.len();
let mut rng = rand::rng();
for _ in 0..FILENAME_LENGTH {
let index = rng.random_range(0..=some_chars_length);
let rando_char = some_chars.chars().nth(index);
if let Some(c) = rando_char {
filename.push(c);
}
}
format!("{filename}{file_extension}")
} else {
format!("coverart-output{file_extension}")
};
Ok(filename)
}
pub mod io {
use std::io::Read;
+1
View File
@@ -7,6 +7,7 @@ pub mod song;
pub mod token;
pub mod types;
pub mod user;
pub mod util;
pub mod init {
pub fn is_id_valid(num: &i32) -> bool {
+8 -14
View File
@@ -2,7 +2,7 @@ use std::default::Default;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize, utoipa::ToSchema)]
#[derive(Clone, Debug, Default, Deserialize, Serialize, utoipa::ToSchema)]
pub struct LoginResult {
pub id: uuid::Uuid,
pub username: String,
@@ -12,20 +12,14 @@ pub struct LoginResult {
pub expiration: i64,
}
impl Default for LoginResult {
fn default() -> Self {
LoginResult {
id: uuid::Uuid::nil(),
username: String::new(),
token: String::new(),
token_type: String::new(),
expiration: -1,
}
}
}
impl LoginResult {
pub fn _to_json(&self) -> Result<String, serde_json::Error> {
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(&self)
}
pub fn token_expired(&self) -> bool {
let current_time = time::OffsetDateTime::now_utc();
let expired = time::OffsetDateTime::from_unix_timestamp(self.expiration).unwrap();
current_time > expired
}
}
+28 -26
View File
@@ -39,8 +39,8 @@ pub struct Song {
pub track_count: i32,
#[serde(skip_serializing_if = "String::is_empty")]
pub audio_type: String,
#[serde(skip_serializing_if = "String::is_empty")]
pub date_created: String,
#[serde(with = "time::serde::rfc3339::option")]
pub date_created: Option<time::OffsetDateTime>,
#[serde(skip_serializing_if = "String::is_empty")]
pub filename: String,
#[serde(skip_serializing_if = "init::is_uuid_nil")]
@@ -69,27 +69,24 @@ impl Song {
}
}
/// Gets the path of a Song
pub fn song_path(&self) -> Result<String, std::io::Error> {
if self.directory.is_empty() {
return Err(std::io::Error::other("Directory does not exist"));
return Err(std::io::Error::other(
crate::constants::error::DIRECTORY_NOT_INITIALIZED,
));
} else if self.filename.is_empty() {
return Err(std::io::Error::other(
crate::constants::error::FILENAME_NOT_INITIALIZED,
));
}
let directory = &self.directory;
let mut buffer: String = directory.clone();
let last_index = directory.len() - 1;
if let Some(character) = directory.chars().nth(last_index) {
if character != '/' {
buffer += "/";
}
buffer += &self.filename.clone();
Ok(buffer)
} else {
Err(std::io::Error::other(
"Could not access last character of directory",
))
match crate::util::concatenate_path(directory, &self.filename, last_index) {
Ok(path) => Ok(path),
Err(err) => Err(err),
}
}
@@ -128,14 +125,15 @@ impl Song {
}
}
/// Generates a filename. In order to save a song to the filesystem, the song must have
/// a directory and filename
pub fn generate_filename(typ: types::MusicTypes, randomize: bool) -> String {
/// Generates a filename. In order to save a song to the filesystem
pub fn generate_filename(
typ: types::MusicTypes,
randomize: bool,
) -> Result<String, std::io::Error> {
let file_extension = match typ {
types::MusicTypes::DefaultMusicExtension => {
String::from(constants::file_extensions::audio::DEFAULTMUSICEXTENSION)
}
types::MusicTypes::WavExtension => {
String::from(constants::file_extensions::audio::WAVEXTENSION)
}
@@ -145,25 +143,29 @@ pub fn generate_filename(typ: types::MusicTypes, randomize: bool) -> String {
types::MusicTypes::MPThreeExtension => {
String::from(constants::file_extensions::audio::MPTHREEEXTENSION)
}
types::MusicTypes::None => return Err(std::io::Error::other("Unsupported MusicTypes")),
};
if randomize {
let mut filename: String = String::new();
let filename: String = if randomize {
let mut filename: String = String::from("track-");
let some_chars: String = String::from("abcdefghij0123456789");
let some_chars_length = some_chars.len();
let mut rng = rand::rng();
for _ in 0..FILENAME_LENGTH {
let index = rng.random_range(0..=19);
let index = rng.random_range(0..=some_chars_length);
let rando_char = some_chars.chars().nth(index);
if let Some(c) = rando_char {
filename.push(c);
}
}
filename + &file_extension
format!("{filename}{file_extension}")
} else {
"track-output".to_string() + &file_extension
}
format!("track-output{file_extension}")
};
Ok(filename)
}
/// I/O operations for songs
+12 -18
View File
@@ -2,7 +2,7 @@ use std::default::Default;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Token {
pub scope: String,
pub expiration: i64,
@@ -27,23 +27,16 @@ pub struct AccessToken {
pub message: String,
}
impl Default for Token {
fn default() -> Self {
Token {
scope: String::new(),
expiration: -1,
audience: String::new(),
issuer: String::new(),
issued: -1,
}
}
}
impl AccessToken {
/// Get the token fit for Bearer authentication
pub fn bearer_token(&self) -> String {
let mut token: String = String::from("Bearer ");
token += &self.token.clone();
token
format!("Bearer {}", self.token)
}
pub fn token_expired(&self) -> bool {
let current_time = time::OffsetDateTime::now_utc();
let expired = time::OffsetDateTime::from_unix_timestamp(self.expiration).unwrap();
current_time > expired
}
}
@@ -52,9 +45,10 @@ impl Token {
serde_json::to_string_pretty(&self)
}
// TODO: Implement
pub fn token_expired(&self) -> bool {
false
let current_time = time::OffsetDateTime::now_utc();
let expired = time::OffsetDateTime::from_unix_timestamp(self.expiration).unwrap();
current_time > expired
}
pub fn contains_scope(&self, des_scope: &String) -> bool {
+10
View File
@@ -1,6 +1,16 @@
#[derive(Debug)]
pub enum MusicTypes {
DefaultMusicExtension,
WavExtension,
FlacExtension,
MPThreeExtension,
None,
}
#[derive(Debug)]
pub enum CoverArtTypes {
PngExtension,
JpegExtension,
JpgExtension,
None,
}
+19
View File
@@ -0,0 +1,19 @@
pub fn concatenate_path(
directory: &str,
filename: &str,
last_index: usize,
) -> Result<String, std::io::Error> {
if let Some(character) = directory.chars().nth(last_index) {
let buffer: String = if character != '/' {
format!("{directory}/")
} else {
String::from(directory)
};
Ok(format!("{buffer}{filename}"))
} else {
Err(std::io::Error::other(
crate::constants::error::LAST_CHARACTER_IN_DIRECTORY,
))
}
}
+11 -2
View File
@@ -107,12 +107,21 @@ mod song_tests {
};
assert_eq!(song.directory.is_empty(), false);
song_cpy.filename = song::generate_filename(types::MusicTypes::FlacExtension, true);
match song::generate_filename(types::MusicTypes::FlacExtension, true) {
Ok(filename) => {
song_cpy.filename = filename;
}
Err(err) => {
assert!(false, "Error generatig filename: {err:?}");
}
};
println!("Directory: {:?}", song_cpy.directory);
println!("File to be created: {:?}", song_cpy.filename);
match song::io::copy_song(&song, &mut song_cpy) {
Ok(_) => {}
Ok(_) => {
println!("Song copied");
}
Err(err) => {
assert!(false, "Error copying song: Error: {err:?}")
}