diff --git a/src/checks/mod.rs b/src/checks/mod.rs new file mode 100644 index 0000000..bf2396a --- /dev/null +++ b/src/checks/mod.rs @@ -0,0 +1,114 @@ +/* + * MIT License + * + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +pub mod osc; + +use console::style; +use std::fmt::{Display, Formatter}; + +pub enum CheckNotice { + /// This will result in Error if importing file and has a support code + ErrorWithCode { + code: String, + description: String, + line: Option, + example: Option, + }, + /// This will result in Error if importing file + Error { + description: String, + line: Option, + }, + #[allow(dead_code)] + /// Other known issues + Warning { + description: String, + line: Option, + }, +} + +impl Display for CheckNotice { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + CheckNotice::ErrorWithCode { + code, + description, + line, + example, + } => match line { + Some(line) => write!( + f, + "{} ({}) at Line {}: {}{}", + style("ERROR").red().bold(), + code, + line, + description, + match example { + Some(example) => format!(" -> '{}'", style(example).dim()), + _ => String::new(), + } + ), + None => write!( + f, + "{} ({}): {}{}", + style("ERROR").red().bold(), + code, + description, + match example { + Some(example) => format!(" -> '{}'", style(example).dim()), + _ => String::new(), + } + ), + }, + CheckNotice::Error { description, line } => match line { + Some(line) => write!( + f, + "{} at Line {}: {}", + style("ERROR").red().bold(), + line, + description + ), + None => write!(f, "{}: {}", style("ERROR").red().bold(), description), + }, + CheckNotice::Warning { description, line } => match line { + Some(line) => write!( + f, + "{} at Line {}: {}", + style("WARNING").yellow().bold(), + line, + description + ), + None => write!(f, "{}: {}", style("WARNING").yellow().bold(), description), + }, + } + } +} + +pub trait Checkable { + fn check(&self) -> Vec; +} + +pub trait Fixable { + fn fix(&mut self) -> bool; +} diff --git a/src/checks/osc.rs b/src/checks/osc.rs new file mode 100644 index 0000000..8ec9a97 --- /dev/null +++ b/src/checks/osc.rs @@ -0,0 +1,87 @@ +/* + * MIT License + * + * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use crate::checks::{CheckNotice, Checkable}; +use crate::model::onkostar_editor::OnkostarEditor; +use std::fs; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; +use std::str::FromStr; + +pub fn check(file: &Path) -> Vec { + let mut result = match File::open(file) { + Ok(file) => BufReader::new(file) + .lines() + .enumerate() + .flat_map(|(line, content)| match content { + Ok(content) => check_line(line, content), + _ => { + return vec![CheckNotice::Error { + description: "Cannot read line".to_string(), + line: Some(line), + }] + } + }) + .collect::>(), + _ => { + return vec![CheckNotice::Error { + description: "Kann Datei nicht lesen".to_string(), + line: None, + }] + } + }; + + let inner_checks = &mut match fs::read_to_string(file) { + Ok(content) => match OnkostarEditor::from_str(content.as_str()) { + Ok(data) => data.check(), + Err(err) => vec![CheckNotice::Error { + description: format!("Interner Fehler: {}", err), + line: None, + }], + }, + _ => vec![CheckNotice::Error { + description: "Kann Datei nicht lesen".to_string(), + line: None, + }], + }; + result.append(inner_checks); + + result +} + +fn check_line(line: usize, content: String) -> Vec { + let mut result = vec![]; + + if content.contains(" ") { + result.append(&mut vec![CheckNotice::ErrorWithCode { + code: "OSTARSUPP-13334".to_string(), + description: "Leerzeichen am Ende der Plausibilitätsregel-Bezeichnung".to_string(), + line: Some(line), + example: Some(content.trim().to_string()), + }]) + } + + result +} diff --git a/src/main.rs b/src/main.rs index f34d635..88cbf8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,9 +28,10 @@ use std::fs; use std::fs::OpenOptions; use std::io::Write; use std::ops::Add; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; +use crate::checks::osc::check; use clap::Parser; use console::style; use dialoguer::Confirm; @@ -40,9 +41,9 @@ use sha256::digest; use crate::cli::{Cli, SubCommand}; use crate::model::onkostar_editor::OnkostarEditor; -use crate::model::Checkable; use crate::profile::Profile; +mod checks; mod cli; mod model; mod profile; @@ -259,8 +260,7 @@ fn main() -> Result<(), Box> { }; } SubCommand::Check { file } => { - read_inputfile(file)? - .check() + check(Path::new(file.as_str())) .iter() .for_each(|check_notice| println!("{}", check_notice)); } diff --git a/src/model/data_form.rs b/src/model/data_form.rs index 56e89b2..baacec2 100644 --- a/src/model/data_form.rs +++ b/src/model/data_form.rs @@ -28,6 +28,7 @@ use std::collections::HashSet; use console::style; use serde::{Deserialize, Serialize}; +use crate::checks::{CheckNotice, Checkable}; use crate::model::onkostar_editor::OnkostarEditor; use crate::model::requirements::{Requirement, Requires}; use crate::model::{ @@ -380,6 +381,12 @@ impl FolderContent for DataForm { } } +impl Checkable for DataForm { + fn check(&self) -> Vec { + vec![] + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct DataCatalogues { diff --git a/src/model/mod.rs b/src/model/mod.rs index 98d056a..eae9980 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -24,12 +24,12 @@ use std::cmp::Ordering; use std::collections::hash_map::DefaultHasher; -use std::fmt::{Debug, Display, Formatter}; +use std::fmt::Debug; use std::hash::{Hash, Hasher}; -use crate::model::requirements::Requires; use serde::{Deserialize, Serialize}; +use crate::model::requirements::Requires; use crate::profile::{FormField, FormReference, Profile}; pub mod data_catalogue; @@ -329,25 +329,3 @@ pub trait FolderContent { "ONKOSTAR Bibliothek" == self.get_library_folder() } } - -pub enum CheckNotice { - /// This will result in Error if importing file - Error { code: String, description: String }, - /// Other known issues - Warning { description: String }, -} - -impl Display for CheckNotice { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - CheckNotice::Error { code, description } => { - write!(f, "[ERROR] ({}) {}", code, description) - } - CheckNotice::Warning { description } => write!(f, "[WARNING] {}", description), - } - } -} - -pub trait Checkable { - fn check(&self) -> Vec; -} diff --git a/src/model/onkostar_editor.rs b/src/model/onkostar_editor.rs index 20a4df8..f612ef1 100644 --- a/src/model/onkostar_editor.rs +++ b/src/model/onkostar_editor.rs @@ -30,14 +30,13 @@ use console::style; use quick_xml::de::from_str; use serde::{Deserialize, Serialize}; +use crate::checks::{CheckNotice, Checkable}; use crate::model::data_catalogue::DataCatalogue; use crate::model::data_form::DataForm; use crate::model::property_catalogue::PropertyCatalogue; use crate::model::requirements::Requires; use crate::model::unterformular::Unterformular; -use crate::model::{ - CheckNotice, Checkable, Comparable, FolderContent, FormEntryContainer, Listable, Sortable, -}; +use crate::model::{Comparable, FolderContent, FormEntryContainer, Listable, Sortable}; use crate::profile::Profile; #[derive(Serialize, Deserialize, Debug)] @@ -413,7 +412,23 @@ impl FromStr for OnkostarEditor { impl Checkable for OnkostarEditor { fn check(&self) -> Vec { - vec![] + let mut result = self + .editor + .data_form + .iter() + .flat_map(|entity| entity.check()) + .collect::>(); + + let other = &mut self + .editor + .unterformular + .iter() + .flat_map(|entity| entity.check()) + .collect::>(); + + result.append(other); + + result } } diff --git a/src/model/unterformular.rs b/src/model/unterformular.rs index 423c8fb..1ca3cf7 100644 --- a/src/model/unterformular.rs +++ b/src/model/unterformular.rs @@ -25,6 +25,7 @@ use std::cmp::Ordering; use std::collections::HashSet; +use crate::checks::{CheckNotice, Checkable}; use console::style; use serde::{Deserialize, Serialize}; @@ -377,6 +378,12 @@ impl FolderContent for Unterformular { } } +impl Checkable for Unterformular { + fn check(&self) -> Vec { + vec![] + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] pub struct DataCatalogues {