use std::path::{Component, Path, PathBuf};
use uuid::Uuid;
pub const PICTURES_DIR: &str = "pictures";
pub const EXTENSIONS: [&str; 4] = ["png", "jpg", "jpeg", "svg"];
pub fn is_picture_path(path: &Path) -> bool {
let inside = path
.components()
.all(|part| matches!(part, Component::Normal(_)));
let picture = path.extension().is_some_and(|extension| {
EXTENSIONS
.iter()
.any(|known| extension.eq_ignore_ascii_case(known))
});
inside && picture && path.components().next().is_some()
}
pub fn new_picture_path(extension: &str) -> PathBuf {
Path::new(PICTURES_DIR).join(format!(
"{}.{}",
Uuid::new_v4(),
extension.to_ascii_lowercase()
))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pictures_inside_the_repository_are_accepted() {
assert!(is_picture_path(Path::new("backgrounds/stage.svg")));
assert!(is_picture_path(Path::new("pictures/lamp.PNG")));
}
#[test]
fn paths_leaving_the_repository_are_refused() {
assert!(!is_picture_path(Path::new("/etc/stage.png")));
assert!(!is_picture_path(Path::new("../stage.png")));
assert!(!is_picture_path(Path::new("pictures/../../stage.png")));
}
#[test]
fn files_that_are_no_pictures_are_refused() {
assert!(!is_picture_path(Path::new("projects/show.json")));
assert!(!is_picture_path(Path::new("pictures/stage")));
}
#[test]
fn a_new_picture_is_named_for_its_kind() {
let path = new_picture_path("JPG");
assert!(path.starts_with(PICTURES_DIR));
assert_eq!(path.extension().and_then(|e| e.to_str()), Some("jpg"));
assert!(is_picture_path(&path));
}
}