Banner style is no longer a generated file, public page gets appearance as CSS variables. Fixes #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 21:42:00 +02:00
co-authored by Claude Opus 5.5
parent 5683acc101
commit 1a1688d322
19 changed files with 132 additions and 148 deletions
+36 -2
View File
@@ -741,14 +741,29 @@ pub struct Appearance {
id: i32,
pub banner: Option<String>,
pub text: Option<String>,
pub title: Option<String>,
pub css_name: Option<String>
pub title: Option<String>
}
impl Appearance {
pub fn id(&self) -> i32 {
self.id
}
/// CSS variables for the banner of the public page, used as its `style` attribute.
/// The styles themselves are in `assets/css/public.css`.
pub fn banner_style(&self) -> String {
match &self.banner {
Some(banner) if is_css_safe_file_name(banner) => format!("--rz-banner-image: url('/data/{}')", banner),
_ => String::new()
}
}
}
/// The value is put into a `style` attribute, so it must not be able to end the `url()` or the declaration
fn is_css_safe_file_name(name: &str) -> bool {
!name.is_empty()
&& !name.starts_with('.')
&& name.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_' || c == '.')
}
pub fn validate_closing_time(time: &ClosingTime) -> Result<(), ValidationError> {
@@ -1272,6 +1287,25 @@ mod tests {
assert_eq!(SlotType::Day.to_string(), "Day");
}
#[test]
fn banner_style_sets_image_variable() {
let appearance = Appearance { banner: Some("my-banner_1.jpg".to_string()), ..Default::default() };
assert_eq!(appearance.banner_style(), "--rz-banner-image: url('/data/my-banner_1.jpg')");
}
#[test]
fn banner_style_is_empty_without_banner() {
assert_eq!(Appearance::default().banner_style(), "");
}
#[test]
fn banner_style_ignores_unsafe_file_names() {
for name in ["", "a'); color: red; x: url('.jpg", "a b.jpg", "../config.toml", "a/b.jpg", "a\\b.jpg", "a\"b.jpg", "a;b.jpg", "a)b.jpg", ".hidden"] {
let appearance = Appearance { banner: Some(name.to_string()), ..Default::default() };
assert_eq!(appearance.banner_style(), "", "name: {:?}", name);
}
}
#[test]
fn enum_defaults() {
assert_eq!(ReservationState::default(), ReservationState::New);