fix validation

This commit is contained in:
naskya 2024-06-21 03:13:58 +09:00
parent df11f9b432
commit 33592de8f3
Signed by: naskya
GPG key ID: 712D413B3A9FED5C
6 changed files with 68 additions and 33 deletions

View file

@ -22,9 +22,9 @@ pub(crate) enum ConfigVersion {
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum Error { pub(crate) enum Error {
#[error(transparent)] #[error(transparent)]
Migrate(#[from] migrate::ConfigMigrateError), Migrate(#[from] migrate::MigrationError),
#[error(transparent)] #[error(transparent)]
Validate(#[from] validate::ConfigValidateError), Validate(#[from] validate::ValidationError),
} }
pub(crate) async fn run(command: Commands) -> Result<(), Error> { pub(crate) async fn run(command: Commands) -> Result<(), Error> {

View file

@ -5,12 +5,12 @@ mod v20240701;
use super::ConfigVersion; use super::ConfigVersion;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum ConfigMigrateError { pub(crate) enum MigrationError {
#[error(transparent)] #[error(transparent)]
V20240701(#[from] v20240701::Error), V20240701(#[from] v20240701::Error),
} }
pub(super) async fn run(version: ConfigVersion) -> Result<(), ConfigMigrateError> { pub(super) async fn run(version: ConfigVersion) -> Result<(), MigrationError> {
match version { match version {
ConfigVersion::V20240701 => v20240701::run().await?, ConfigVersion::V20240701 => v20240701::run().await?,
} }

View file

@ -394,7 +394,7 @@ fn create_new_client_config(meta: Meta) -> Result<client::Config, Error> {
let mut config = client::Config { let mut config = client::Config {
theme: None, theme: None,
image: None, image: None,
pinned_links: vec![], pinned_links: None,
}; };
if meta.theme_color.is_some() if meta.theme_color.is_some()
@ -438,7 +438,7 @@ pub(super) async fn run() -> Result<(), Error> {
} }
let mut server_toml = let mut server_toml =
fs::File::create_new("config/server.toml").map_err(WriteTomlConfigError::ServerWrite)?; fs::File::create("config/server.toml").map_err(WriteTomlConfigError::ServerWrite)?;
server_toml server_toml
.write( .write(
toml::to_string_pretty(&server_config) toml::to_string_pretty(&server_config)
@ -446,10 +446,10 @@ pub(super) async fn run() -> Result<(), Error> {
.as_bytes(), .as_bytes(),
) )
.map_err(WriteTomlConfigError::ServerWrite)?; .map_err(WriteTomlConfigError::ServerWrite)?;
cprintln!("<g>config/server.toml</> has been created!"); cprintln!("<g!><bold>config/server.toml</></> has been created!");
let mut client_toml = let mut client_toml =
fs::File::create_new("config/client.toml").map_err(WriteTomlConfigError::ClientWrite)?; fs::File::create("config/client.toml").map_err(WriteTomlConfigError::ClientWrite)?;
client_toml client_toml
.write( .write(
toml::to_string_pretty(&client_config) toml::to_string_pretty(&client_config)
@ -457,7 +457,7 @@ pub(super) async fn run() -> Result<(), Error> {
.as_bytes(), .as_bytes(),
) )
.map_err(WriteTomlConfigError::ClientWrite)?; .map_err(WriteTomlConfigError::ClientWrite)?;
cprintln!("<g>config/client.toml</> has been created!"); cprintln!("<g><bold>config/client.toml</></> has been created!");
Ok(()) Ok(())
} }

View file

@ -1,47 +1,73 @@
//! `config validate` subcommand //! `config validate` subcommand
use crate::config::{client, server}; use crate::config::{client, server};
use color_print::cprintln;
use std::{fs, io::Read}; use std::{fs, io::Read};
use validator::{Validate, ValidationErrors}; use validator::Validate;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
pub(crate) enum ConfigValidateError { pub(crate) enum ValidationError {
#[error(transparent)]
Read(#[from] ReadConfigError),
#[error(transparent)]
InvalidConfig(#[from] ValidationErrors),
}
#[derive(thiserror::Error, Debug)]
pub(crate) enum ReadConfigError {
#[error(transparent)] #[error(transparent)]
ReadFile(#[from] std::io::Error), ReadFile(#[from] std::io::Error),
#[error("config/server.toml is not written in the TOML format")] #[error("invalid config file")]
InvalidServerTomlFormat(#[source] toml::de::Error), InvalidConfig,
#[error("config/client.toml is not written in the TOML format")]
InvalidClientTomlFormat(#[source] toml::de::Error),
} }
pub(super) fn run() -> Result<(), ConfigValidateError> { #[derive(thiserror::Error, Debug)]
read_server_toml()?.validate()?; enum ReadError {
read_client_toml()?.validate()?; #[error(transparent)]
Ok(()) ReadFile(#[from] std::io::Error),
#[error("the config file is not written in the correct format")]
InvalidFormat(#[from] toml::de::Error),
} }
fn read_server_toml() -> Result<server::Config, ReadConfigError> { pub(super) fn run() -> Result<(), ValidationError> {
let server_validation_result = match read_server_toml() {
Ok(config) => config.validate().map_err(|err| {
cprintln!("<r!><bold>config/server.toml is invalid.</></>\n{}", err);
ValidationError::InvalidConfig
}),
Err(ReadError::InvalidFormat(err)) => {
cprintln!("<r!><bold>config/server.toml is invalid.</></>\n{}", err);
Err(ValidationError::InvalidConfig)
}
Err(ReadError::ReadFile(err)) => Err(ValidationError::ReadFile(err)),
};
let client_validation_result = match read_client_toml() {
Ok(config) => config.validate().map_err(|err| {
cprintln!("<r!><bold>config/client.toml is invalid.</></>\n{}", err);
ValidationError::InvalidConfig
}),
Err(ReadError::InvalidFormat(err)) => {
cprintln!("<r!><bold>config/client.toml is invalid.</></>\n{}", err);
Err(ValidationError::InvalidConfig)
}
Err(ReadError::ReadFile(err)) => Err(ValidationError::ReadFile(err)),
};
if server_validation_result.is_ok() && client_validation_result.is_ok() {
cprintln!("<g!><bold>config/server.toml and config/client.toml are valid!</></>");
cprintln!("<bold>Note:</> This is only a formal validation, so this does not guarantee that the settings are appropriate.");
}
server_validation_result.and_then(|_| client_validation_result)
}
fn read_server_toml() -> Result<server::Config, ReadError> {
let mut file = fs::File::open("config/server.toml")?; let mut file = fs::File::open("config/server.toml")?;
let mut buffer = String::new(); let mut buffer = String::new();
file.read_to_string(&mut buffer)?; file.read_to_string(&mut buffer)?;
toml::from_str(&buffer).map_err(ReadConfigError::InvalidServerTomlFormat) toml::from_str(&buffer).map_err(ReadError::InvalidFormat)
} }
fn read_client_toml() -> Result<client::Config, ReadConfigError> { fn read_client_toml() -> Result<client::Config, ReadError> {
let mut file = fs::File::open("config/client.toml")?; let mut file = fs::File::open("config/client.toml")?;
let mut buffer = String::new(); let mut buffer = String::new();
file.read_to_string(&mut buffer)?; file.read_to_string(&mut buffer)?;
toml::from_str(&buffer).map_err(ReadConfigError::InvalidClientTomlFormat) toml::from_str(&buffer).map_err(ReadError::InvalidFormat)
} }

View file

@ -10,9 +10,12 @@ use validator::{Validate, ValidationError};
#[derive(Deserialize, Serialize, Validate, Debug)] #[derive(Deserialize, Serialize, Validate, Debug)]
pub struct Config { pub struct Config {
#[validate(nested)]
pub theme: Option<Theme>, pub theme: Option<Theme>,
#[validate(nested)]
pub image: Option<Image>, pub image: Option<Image>,
pub pinned_links: Vec<WebSite>, #[validate(nested)]
pub pinned_links: Option<Vec<WebSite>>,
} }
#[derive(Deserialize, Serialize, Validate, Debug)] #[derive(Deserialize, Serialize, Validate, Debug)]

View file

@ -6,15 +6,21 @@
// does not take care of it. // does not take care of it.
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::{Validate, ValidationErrors};
#[derive(Deserialize, Serialize, Validate, Debug)] #[derive(Deserialize, Serialize, Validate, Debug)]
pub struct Config { pub struct Config {
#[validate(nested)]
pub info: Option<Info>, pub info: Option<Info>,
#[validate(nested)]
pub timelines: Option<Timelines>, pub timelines: Option<Timelines>,
#[validate(nested)]
pub network: Network, pub network: Network,
#[validate(nested)]
pub database: Database, pub database: Database,
#[validate(nested)]
pub cache_server: CacheServer, pub cache_server: CacheServer,
#[validate(nested)]
pub id: Option<Id>, pub id: Option<Id>,
} }