40 Commits

Author SHA1 Message Date
f3bbef5d22 Bump version 2023-11-10 17:12:56 +01:00
ef8f6ab1b5 Change description and arguments depending on selected features 2023-11-10 16:41:54 +01:00
a1e5133516 Merge pull request #23 from CCC-MF/issue_22
Check form references to previously undefined forms in OSC files
2023-11-10 12:38:39 +01:00
13bcd74f6c Issue #22: Check form references to previously undefined forms in OSC files 2023-11-10 12:36:53 +01:00
6fdbe06106 Add information about the reason 2023-11-10 12:36:04 +01:00
31c162e977 Update profile file for UKM 2023-11-09 13:15:18 +01:00
2413e4b9b8 Improve check output 2023-11-09 13:00:34 +01:00
c9ecb8e944 Add progress bar to OSB file check 2023-11-09 12:11:13 +01:00
774b57d78e Fix required argument conflicts in check sub command 2023-11-09 11:21:24 +01:00
a52eb9742e Merge pull request #21 from CCC-MF/issue_14
Issue #14: Embed existing DNPM profile files
2023-11-09 10:58:28 +01:00
4c76504000 Issue #14: Embed existing DNPM profile files 2023-11-09 10:53:38 +01:00
4676a63c69 Fix warnings for disabled features 2023-11-09 10:42:54 +01:00
e250e330a5 Merge pull request #20 from CCC-MF/issue_19
Check OSC- und OSB-Files for known issues
2023-11-09 09:27:16 +01:00
349b571e09 Issue #19: Do not allow check listing in combination with file check 2023-11-08 16:49:23 +01:00
90423b5b4e Issue #19: Check OSC files within OSB file 2023-11-08 14:38:16 +01:00
d45ded939e Issue #19: Extract method to check content of OSC file 2023-11-08 14:38:02 +01:00
7ab5523f3c Add more checks shown before in list subcommand 2023-11-08 12:35:58 +01:00
f02ea9b065 Show issue counts ahead of issue list 2023-11-08 12:10:42 +01:00
a08abd7688 Make version entries and categories optional in property catalogue 2023-11-08 11:56:07 +01:00
bf7b8cd9ba Add 'PunkteKategorie' to model 2023-11-07 12:00:21 +01:00
821b30e452 Add information about 'check' sub command 2023-11-07 08:13:45 +01:00
6a0a356120 Update issue code and description 2023-11-07 08:10:50 +01:00
352f5e23fc Merge pull request #18 from CCC-MF/issue_15
Checks and fixes for known issues in OSC files
2023-11-06 14:02:32 +01:00
7b13251d34 Issue #15: Add flag '--fix' to modify sub command 2023-11-06 14:00:20 +01:00
6da1c48c28 Issue #15: Show list of available checks 2023-11-06 13:59:08 +01:00
e2d5eedd02 Issue #15: Check OSC files for known issues 2023-11-06 13:31:34 +01:00
a55db66e57 Issue #15: Implement check subcommand cli 2023-11-06 11:52:57 +01:00
dce2a5cdda Merge pull request #17 from CCC-MF/issue_16
Issue #16: Add missing model entries and add optional declaration
2023-11-06 11:46:34 +01:00
93981f7709 Issue #16: Add missing model entries and add optional declaration 2023-11-06 11:44:41 +01:00
b6694b9e53 Add package metadata to generate rpm packages 2023-11-04 11:45:47 +01:00
0e690cbb85 Update quick-qml dependency 2023-11-04 11:45:15 +01:00
0d6525c398 Update dependencies 2023-11-03 21:19:30 +01:00
df643b5e60 Recompile if c header file changed 2023-11-03 20:59:31 +01:00
1746026af8 Declare use within feature flag related part 2023-11-03 20:58:51 +01:00
7cdfe0068f Add information about optional params for unzip-osb command 2023-11-02 21:02:32 +01:00
1f5ec80cc6 Add optional destination dir for OSB file extraction 2023-11-02 20:56:57 +01:00
f851e9c424 Add optional OSB alternative password parameter 2023-11-01 13:29:30 +01:00
7ef1638b58 Update dependencies 2023-10-31 15:09:03 +01:00
4745a75f2e Initial WXS file to build MSI installer package 2023-10-24 12:29:28 +02:00
f089ad0b32 Update Cargo.lock file 2023-10-24 12:28:53 +02:00
19 changed files with 1005 additions and 90 deletions

113
Cargo.lock generated
View File

@@ -148,9 +148,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.4.6" version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@@ -158,9 +158,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.4.6" version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"clap_lex", "clap_lex",
@@ -168,18 +168,18 @@ dependencies = [
[[package]] [[package]]
name = "clap_complete" name = "clap_complete"
version = "4.4.3" version = "4.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7" checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae"
dependencies = [ dependencies = [
"clap", "clap",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.4.2" version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@@ -189,9 +189,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.5.1" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]] [[package]]
name = "console" name = "console"
@@ -214,9 +214,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -303,9 +303,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.5" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@@ -372,14 +372,27 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.0.2" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown", "hashbrown",
] ]
[[package]]
name = "indicatif"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25"
dependencies = [
"console",
"instant",
"number_prefix",
"portable-atomic",
"unicode-width",
]
[[package]] [[package]]
name = "inout" name = "inout"
version = "0.1.3" version = "0.1.3"
@@ -389,6 +402,15 @@ dependencies = [
"generic-array", "generic-array",
] ]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.9" version = "1.0.9"
@@ -412,15 +434,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.149" version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.10" version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
[[package]] [[package]]
name = "memchr" name = "memchr"
@@ -437,6 +459,12 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.1" version = "0.32.1"
@@ -448,13 +476,14 @@ dependencies = [
[[package]] [[package]]
name = "osc-variant" name = "osc-variant"
version = "0.5.0" version = "0.7.0"
dependencies = [ dependencies = [
"clap", "clap",
"clap_complete", "clap_complete",
"console", "console",
"deob", "deob",
"dialoguer", "dialoguer",
"indicatif",
"quick-xml", "quick-xml",
"serde", "serde",
"serde_yaml", "serde_yaml",
@@ -497,6 +526,12 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "portable-atomic"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bccab0e7fd7cc19f820a1c8c91720af652d0c88dc9664dd72aef2614f04af3b"
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
@@ -514,9 +549,9 @@ dependencies = [
[[package]] [[package]]
name = "quick-xml" name = "quick-xml"
version = "0.30.0" version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
dependencies = [ dependencies = [
"memchr", "memchr",
"serde", "serde",
@@ -539,9 +574,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.3.5" version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
] ]
@@ -554,9 +589,9 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.20" version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"errno", "errno",
@@ -573,18 +608,18 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.189" version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.189" version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -593,9 +628,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.9.25" version = "0.9.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
@@ -653,9 +688,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.38" version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -664,9 +699,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.8.0" version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@@ -715,9 +750,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.33.0" version = "1.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bytes", "bytes",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "osc-variant" name = "osc-variant"
version = "0.6.0" version = "0.7.0"
edition = "2021" edition = "2021"
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"] authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
description = "Anwendung zum Anpassen einer OSC-Datei an einen Standort" description = "Anwendung zum Anpassen einer OSC-Datei an einen Standort"
@@ -16,10 +16,11 @@ members = ["libs/deob"]
clap = { version = "4.4", features = ["std", "help", "usage", "derive", "error-context"], default-features = false } clap = { version = "4.4", features = ["std", "help", "usage", "derive", "error-context"], default-features = false }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9" serde_yaml = "0.9"
quick-xml = { version = "0.30", features = ["escape-html", "serialize"], default-features = false } quick-xml = { version = "0.31", features = ["escape-html", "serialize"], default-features = false }
console = "0.15" console = "0.15"
sha256 = "1.4" sha256 = "1.4"
dialoguer = "0.11" dialoguer = "0.11"
indicatif = "0.17"
deob = { path = "./libs/deob", optional = true } deob = { path = "./libs/deob", optional = true }
zip = { version = "0.6", optional = true } zip = { version = "0.6", optional = true }
@@ -46,3 +47,9 @@ assets = [
["target/release/osc-variant", "usr/bin/", "755"], ["target/release/osc-variant", "usr/bin/", "755"],
["completion/osc-variant.bash", "etc/bash_completion.d/", "644"] ["completion/osc-variant.bash", "etc/bash_completion.d/", "644"]
] ]
[package.metadata.generate-rpm]
assets = [
{ source = "target/release/osc-variant", dest = "/usr/bin/", mode = "755" },
{ source = "completion/osc-variant.bash", dest = "/etc/bash_completion.d/", mode = "644" }
]

View File

@@ -91,6 +91,15 @@ Ohne Profildatei wird die Datei lediglich eingelesen, Leerzeichen am Ende eines
Ohne eine Angabe der Ausgabedatei wird auf die Standardausgabe ausgegeben. Ohne eine Angabe der Ausgabedatei wird auf die Standardausgabe ausgegeben.
##### Enthaltene Profile
Die im Ordner [`examples/`](/examples) enthaltenen Profile für Standorte sind in der ausführbaren Anwendung enthalten
und die Dateien müssen nicht explizit als Datei vorliegen:
* `--profile examples/dnpm-ukm.yml` => `--profile UKM`
* `--profile examples/dnpm-ukw.yml` => `--profile UKW`
* `--profile examples/dnpm-umg.yml` => `--profile UMG`
#### Unterbefehl `unzip-osb` #### Unterbefehl `unzip-osb`
Ab Version 0.6.0 ist die Anwendung zudem in der Lage, die für eine Aktualisierung der OS-Bibliothek genutzten OSB-Dateien zu entpacken: Ab Version 0.6.0 ist die Anwendung zudem in der Lage, die für eine Aktualisierung der OS-Bibliothek genutzten OSB-Dateien zu entpacken:
@@ -99,6 +108,17 @@ Ab Version 0.6.0 ist die Anwendung zudem in der Lage, die für eine Aktualisieru
osc-variant unzip-osb OSBIB-6.10.osb osc-variant unzip-osb OSBIB-6.10.osb
``` ```
Dieser Befehl kennt die beiden optionalen Parameter
* `-d`: Optionale Angabe des Zielverzeichnisses. Wenn keine Angabe vorhanden ist, wird das aktuelle Verzeichnis verwendet.
* `-p`/`--password`: Optionale Angabe des Passworts zum Entpacken der OSB-Datei.
#### Unterbefehl `check`
Der Unterbefehl `check` prüft eine OSC-Datei auf bekannte Probleme und gibt eine Liste mit erkannten Problemen aus.
Eine Liste mit bekannten Problemen wird mit `check --list` ausgegeben.
#### Kompakte Ausgabe #### Kompakte Ausgabe
OSC-Dateien sind XML-Dateien. Diese Anwendung ermöglicht optional die Ausgabe als kompaktere XML-Datei ohne Zeilenumbrüche. OSC-Dateien sind XML-Dateien. Diese Anwendung ermöglicht optional die Ausgabe als kompaktere XML-Datei ohne Zeilenumbrüche.

View File

@@ -7,6 +7,7 @@ forms:
scripts_code: | scripts_code: |
setFieldValue('AnmeldedatumMTB', getFieldValue('MTB').MTBTermin); setFieldValue('AnmeldedatumMTB', getFieldValue('MTB').MTBTermin);
setFieldValue('WHOGrad', getFieldValue('MTB').WHOGrad); setFieldValue('WHOGrad', getFieldValue('MTB').WHOGrad);
setFieldValue('Leitlinienstatus', getFieldValue('MTB').Leitlinienstatus);
- name: 'DNPM Therapieplan' - name: 'DNPM Therapieplan'
form_references: form_references:
- name: referstemtb - name: referstemtb

View File

@@ -27,5 +27,6 @@ use std::io::Error;
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
cc::Build::new().file("src/deob.c").compile("deob"); cc::Build::new().file("src/deob.c").compile("deob");
println!("cargo:rerun-if-changed=src/deob.c"); println!("cargo:rerun-if-changed=src/deob.c");
println!("cargo:rerun-if-changed=src/deob.h");
Ok(()) Ok(())
} }

30
osc-variant.wxs Normal file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*"
Language="1033"
Manufacturer="CCC Mainfranken"
Name="OSC-Variant"
UpgradeCode="{83088581-5db3-49a2-8932-27da356818c7}"
Version="0.6.0">
<Package InstallScope="perMachine" Compressed="yes" />
<MediaTemplate EmbedCab="yes" />
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLFOLDER" Name="osc-variant">
<Component Id="MainExecutable" Guid="*">
<File Id="OscVariantExe" Name="osc-variant.exe" KeyPath="yes" Source="target/x86_64-pc-windows-gnu/release/osc-variant.exe" />
<File Id="LicenseTxt" Name="LICENSE.txt" Source="LICENSE.txt" />
</Component>
</Directory>
</Directory>
</Directory>
<Feature Id="Complete">
<ComponentRef Id="MainExecutable" />
</Feature>
</Product>
</Wix>

245
src/checks/mod.rs Normal file
View File

@@ -0,0 +1,245 @@
/*
* 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 std::fmt::{Display, Formatter};
use std::path::Path;
use console::style;
#[cfg(feature = "unzip-osb")]
pub mod osb;
pub mod osc;
#[allow(dead_code)]
pub enum CheckNotice {
/// This will result in Error if importing file and has a support code
ErrorWithCode {
code: String,
description: String,
line: Option<usize>,
example: Option<String>,
},
/// This will result in Error if importing file
Error {
description: String,
line: Option<usize>,
},
/// Other known issues
Warning {
description: String,
line: Option<usize>,
},
/// Other known issues
Info {
description: String,
line: Option<usize>,
},
/// Ok
Ok(String),
}
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,
"{: <7} ({}) at Line {}: {}{}",
style("ERROR").red().bold(),
code,
line,
description,
match example {
Some(example) => format!("\n 🔥 '{}'", style(example).dim()),
_ => String::new(),
}
),
None => write!(
f,
"{: <7} ({}): {}{}",
style("ERROR").red().bold(),
code,
description,
match example {
Some(example) => format!("\n 🔥 '{}'", style(example).dim()),
_ => String::new(),
}
),
},
CheckNotice::Error { description, line } => match line {
Some(line) => write!(
f,
"{: <7} at Line {}: {}",
style("ERROR").red().bold(),
line,
description
),
None => write!(f, "{: <7} {}", style("ERROR").red().bold(), description),
},
CheckNotice::Warning { description, line } => match line {
Some(line) => write!(
f,
"{: <7} at Line {}: {}",
style("WARNING").yellow().bold(),
line,
description
),
None => write!(
f,
"{: <7} {}",
style("WARNING").yellow().bold(),
description
),
},
CheckNotice::Info { description, line } => match line {
Some(line) => write!(
f,
"{: <7} at Line {}: {}",
style("INFO").blue().bold(),
line,
description
),
None => write!(f, "{: <7} {}", style("INFO").blue().bold(), description),
},
CheckNotice::Ok(msg) => write!(f, "{: <7} {}", style("OK").green(), msg),
}
}
}
pub trait Checkable {
fn check(&self) -> Vec<CheckNotice>;
}
pub trait Fixable {
fn fix(&mut self) -> bool;
}
#[allow(unused_variables)]
pub fn check_file(file: &Path, password: Option<String>) -> Result<Vec<CheckNotice>, CheckNotice> {
match file.extension() {
Some(ex) => match ex.to_str() {
#[cfg(feature = "unzip-osb")]
Some("osb") => match password {
Some(password) => osb::check_file(file, password.as_str()),
None => {
use deob::deobfuscate;
osb::check_file(file, deobfuscate(env!("OSB_KEY").trim()).as_str())
}
},
Some("osc") => osc::check_file(file),
_ => Err(CheckNotice::Error {
description: "Keine prüfbare Datei".to_string(),
line: None,
}),
},
_ => Err(CheckNotice::Error {
description: "Keine prüfbare Datei".to_string(),
line: None,
}),
}
}
pub fn print_checks() {
println!(
"{}",
style("Die folgenden Probleme sind bekannt\n")
.yellow()
.bold()
);
struct Problem<'a> {
code: &'a str,
name: &'a str,
description: &'a str,
fixable: bool,
}
impl<'a> Display for Problem<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {} {}\n\n{}",
style(self.code).bold(),
style(self.name).underlined(),
match self.fixable {
true => style("(Behebbar)").green(),
false => style("(Nicht behebbar)").red(),
},
self.description
)
}
}
vec![
Problem {
code: "2023-0001",
name: "Unterformular mit Markierung 'hat Unterformulare'",
description: " Aktuell gibt es keine Unterformulare in Unterformularen, daher\n \
sollte dies nicht vorkommen.\n\n \
Eine mögliche Ursache ist die Speicherung eines Unterformulars als Formular.",
fixable: false,
},
Problem {
code: "2023-0002",
name: "Formular hat keine Angabe zum Prozedurdatum",
description: " Formulare benötigen die Angabe des Prozedurdatums, anderenfalls\n \
führt dies zu Problemen in Onkostar.\n\n \
Unterformulare können ein Prozedurdatum haben, müssen es aber nicht.\n\n \
Eine mögliche Ursache ist die Speicherung eines Formulars als Unterformular.",
fixable: false,
},
Problem {
code: "2023-0003",
name: "Leerzeichen am Ende der Plausibilitätsregel-Bezeichnung (OSTARSUPP-13334)",
description:
" Treten Leerzeichen am Ende der Plausibilitätsregel-Bezeichnung auf,\n \
führt dies zu Fehlern beim Import der OSC-Datei.\n\n \
Das Problem wird beim Verwenden des Unterbefehls 'modify' automatisch\n \
behoben und Leerzeichen entfernt.
",
fixable: true,
},
Problem {
code: "2023-0004",
name: "Verweis auf noch nicht definiertes Formular (OSTARSUPP-13212)",
description: " Wenn ein Formular einen Verweis auf ein anderes Formular enthält,\n \
das nicht vor diesem Formular in der OSC-Datei definiert ist, wird der\n \
Formularverweis beim Import der OSC-Datei nicht übernommen.\n\n \
Dies kann bei wechselseitiger Abhängigkeit zwischen zwei (Unter-)Formularen\n \
auftreten.\n\n \
In diesem Fall kann ein erneuter/zweiter Import helfen, da das Onkostar in\n \
diesem Fall alle Formulare importiert hat und der Formularverweis dann \n \
gespeichert werden kann.
",
fixable: false,
},
]
.iter()
.for_each(|problem| println!("{}\n", problem))
}

108
src/checks/osb.rs Normal file
View File

@@ -0,0 +1,108 @@
/*
* 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 std::fs;
use std::io::Read;
use std::path::Path;
use indicatif::ProgressBar;
use crate::checks::{osc, CheckNotice};
#[cfg(feature = "unzip-osb")]
pub fn check_file(file: &Path, password: &str) -> Result<Vec<CheckNotice>, CheckNotice> {
let file = match fs::File::open(file) {
Ok(file) => file,
Err(err) => {
return Err(CheckNotice::Error {
description: format!("Kann Datei nicht lesen: {}", err),
line: None,
});
}
};
let mut archive = match zip::ZipArchive::new(file) {
Ok(file) => file,
Err(err) => {
return Err(CheckNotice::Error {
description: format!("Kann Datei nicht lesen: {}", err),
line: None,
});
}
};
let mut result = vec![];
let progress_bar = ProgressBar::new(archive.len() as u64);
for i in 0..archive.len() {
progress_bar.inc(1);
if let Ok(Ok(mut zip_file)) = archive.by_index_decrypt(i, password.as_bytes()) {
if zip_file.is_file() && zip_file.name().ends_with(".osc") {
let mut buf = String::new();
let _ = zip_file.read_to_string(&mut buf);
match osc::check(buf) {
Ok(ref mut check_result) => {
result.push(CheckNotice::Info {
description: format!("Prüfe Eintrag '{}'", zip_file.name()),
line: None,
});
if check_result.is_empty() {
result.push(CheckNotice::Ok(format!(
"Keine Probleme in '{}' erkannt",
zip_file.name()
)))
}
result.append(check_result)
}
Err(_) => result.push(CheckNotice::Warning {
description: format!(
"Überspringe Eintrag '{}': Inhalt kann nicht geprüft werden",
zip_file.name(),
),
line: None,
}),
};
continue;
}
if zip_file.is_file() {
result.push(CheckNotice::Warning {
description: format!(
"Überspringe Eintrag '{}': Keine OSC-Datei",
zip_file.name()
),
line: None,
})
}
} else {
return Err(CheckNotice::Error {
description: format!("Kann Datei nicht lesen"),
line: None,
});
}
}
progress_bar.finish_and_clear();
Ok(result)
}

78
src/checks/osc.rs Normal file
View File

@@ -0,0 +1,78 @@
/*
* 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 std::fs;
use std::path::Path;
use std::str::FromStr;
use crate::checks::{CheckNotice, Checkable};
use crate::model::onkostar_editor::OnkostarEditor;
pub fn check_file(file: &Path) -> Result<Vec<CheckNotice>, CheckNotice> {
match fs::read_to_string(file) {
Ok(content) => check(content),
_ => Err(CheckNotice::Error {
description: "Kann Datei nicht lesen".to_string(),
line: None,
}),
}
}
pub fn check(content: String) -> Result<Vec<CheckNotice>, CheckNotice> {
let mut result = content
.lines()
.enumerate()
.flat_map(|(line, content)| check_line(line, content.to_string()))
.collect::<Vec<_>>();
let inner_checks = &mut match OnkostarEditor::from_str(content.as_str()) {
Ok(data) => data.check(),
Err(err) => {
return Err(CheckNotice::Error {
description: format!("Interner Fehler: {}", err),
line: None,
})
}
};
result.append(inner_checks);
Ok(result)
}
fn check_line(line: usize, content: String) -> Vec<CheckNotice> {
let mut result = vec![];
if content.contains(" </Bezeichnung>") {
result.append(&mut vec![CheckNotice::ErrorWithCode {
code: "2023-0003".to_string(),
description:
"Leerzeichen am Ende der Plausibilitätsregel-Bezeichnung (OSTARSUPP-13334)"
.to_string(),
line: Some(line),
example: Some(content.trim().to_string()),
}])
}
result
}

View File

@@ -93,6 +93,11 @@ pub enum SubCommand {
help = "Starte interaktiven Dialog zum Modifizieren von OSC-Dateien" help = "Starte interaktiven Dialog zum Modifizieren von OSC-Dateien"
)] )]
interactive: bool, interactive: bool,
#[arg(
long = "fix",
help = "Erweiterte Problembehandlung und Reparatur der OSC-Datei"
)]
fix: bool,
}, },
#[command(about = "Vergleiche zwei Dateien anhand der Revision der enthaltenen Inhalte")] #[command(about = "Vergleiche zwei Dateien anhand der Revision der enthaltenen Inhalte")]
Diff { Diff {
@@ -101,7 +106,36 @@ pub enum SubCommand {
#[arg(long = "strict", help = "Strikter Vergleich des Inhalts")] #[arg(long = "strict", help = "Strikter Vergleich des Inhalts")]
strict: bool, strict: bool,
}, },
#[command(about = if cfg!(feature = "unzip-osb") { "Prüfe eine OSB- oder OSC-Datei auf bekannte Problemen" } else { "Prüfe eine OSC-Datei auf bekannte Problemen" })]
Check {
#[arg(help = "Die zu prüfende Datei", group = "check-file", required = true)]
file: Option<String>,
#[arg(
short = 'p',
long = "password",
help = "Passwort der OSB-Datei (Optional - für OSB-Dateien)",
requires = "check-file",
hide = !cfg!(feature = "unzip-osb")
)]
password: Option<String>,
#[arg(
long = "list",
help = "Prüfe nicht und zeige Liste mit Checks auf bekannte Problemen",
conflicts_with = "check-file"
)]
list: bool,
},
#[cfg(feature = "unzip-osb")] #[cfg(feature = "unzip-osb")]
#[command(about = "Entpackt eine OSB-Datei")] #[command(about = "Entpackt eine OSB-Datei")]
UnzipOsb { file: String }, UnzipOsb {
file: String,
#[arg(
short = 'p',
long = "password",
help = "Passwort der OSB-Datei (Optional)"
)]
password: Option<String>,
#[arg(short = 'd', help = "Zielverzeichnis (Optional)")]
dir: Option<String>,
},
} }

View File

@@ -28,9 +28,10 @@ use std::fs;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::ops::Add; use std::ops::Add;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use crate::checks::{check_file, print_checks, CheckNotice};
use clap::Parser; use clap::Parser;
use console::style; use console::style;
use dialoguer::Confirm; use dialoguer::Confirm;
@@ -42,6 +43,7 @@ use crate::cli::{Cli, SubCommand};
use crate::model::onkostar_editor::OnkostarEditor; use crate::model::onkostar_editor::OnkostarEditor;
use crate::profile::Profile; use crate::profile::Profile;
mod checks;
mod cli; mod cli;
mod model; mod model;
mod profile; mod profile;
@@ -153,13 +155,19 @@ fn main() -> Result<(), Box<dyn Error>> {
sorted, sorted,
strip, strip,
interactive, interactive,
fix,
} => { } => {
let data = &mut read_inputfile(inputfile)?; let data = &mut read_inputfile(inputfile)?;
if let Some(profile) = profile { if let Some(profile) = profile {
let profile = read_profile(profile.clone()).map_err(|_| { let profile = if profile.contains(".") {
FileError::Reading(profile, "Kann Profildatei nicht lesen!".into()) read_profile(profile.clone()).map_err(|_| {
})?; FileError::Reading(profile, "Kann Profildatei nicht lesen!".into())
})?
} else {
Profile::embedded_profile(profile.as_str())?
};
data.apply_profile(&profile); data.apply_profile(&profile);
} }
@@ -189,6 +197,10 @@ fn main() -> Result<(), Box<dyn Error>> {
.unwrap(); .unwrap();
} }
if fix {
// No operation as of now
}
if sorted { if sorted {
data.sorted(); data.sorted();
} }
@@ -257,10 +269,52 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
}; };
} }
SubCommand::Check {
file,
list,
password,
} => {
if list {
print_checks();
} else {
match check_file(Path::new(file.unwrap_or_default().as_str()), password) {
Ok(notices) => {
println!(
"Es wurden {} Probleme gefunden\n",
notices
.iter()
.filter(|notice| match notice {
CheckNotice::ErrorWithCode { .. }
| CheckNotice::Error { .. } => true,
_ => false,
})
.count()
);
notices
.iter()
.for_each(|check_notice| println!("{}", check_notice));
}
Err(err) => {
println!("{}", err)
}
}
}
}
#[cfg(feature = "unzip-osb")] #[cfg(feature = "unzip-osb")]
SubCommand::UnzipOsb { file } => { SubCommand::UnzipOsb {
use crate::unzip_osb::unzip_osb; file,
unzip_osb(file.as_str()) password,
dir,
} => {
use crate::unzip_osb::{unzip_osb, unzip_osb_using_password};
match password {
Some(password) => unzip_osb_using_password(
file.as_str(),
dir.unwrap_or_default().as_str(),
password.as_str(),
),
None => unzip_osb(file.as_str(), dir.unwrap_or_default().as_str()),
}
} }
}; };

View File

@@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor; use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires}; use crate::model::requirements::{Requirement, Requires};
use crate::model::{Comparable, FolderContent, Listable, Ordner, Sortable}; use crate::model::{Ansichten, Comparable, FolderContent, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@@ -58,6 +58,9 @@ pub struct DataCatalogue {
entries: Entries, entries: Entries,
#[serde(rename = "Ordner")] #[serde(rename = "Ordner")]
ordner: Ordner, ordner: Ordner,
#[serde(rename = "Ansichten", default)]
#[serde(skip_serializing_if = "Option::is_none")]
ansichten: Option<Ansichten>,
} }
impl Listable for DataCatalogue { impl Listable for DataCatalogue {

View File

@@ -28,12 +28,14 @@ use std::collections::HashSet;
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::checks::CheckNotice::ErrorWithCode;
use crate::checks::{CheckNotice, Checkable};
use crate::model::onkostar_editor::OnkostarEditor; use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires}; use crate::model::requirements::{Requirement, Requires};
use crate::model::{ use crate::model::{
apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries, apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries,
Filter, FolderContent, FormEntry, FormEntryContainer, Listable, MenuCategory, Filter, FolderContent, FormEntry, FormEntryContainer, Kennzahlen, Listable, MenuCategory,
PlausibilityRules, RefEntries, Script, Sortable, PlausibilityRules, PunkteKategorien, RefEntries, Script, Sortable,
}; };
use crate::model::{Haeufigkeiten, Ordner}; use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile; use crate::profile::Profile;
@@ -80,18 +82,26 @@ pub struct DataForm {
#[serde(rename = "EmailTemplate")] #[serde(rename = "EmailTemplate")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
mail_template: Option<String>, mail_template: Option<String>,
#[serde(rename = "ErkrankungText")] #[serde(rename = "ErkrankungText", default)]
erkrankung_text: String, #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_text: Option<String>,
#[serde(rename = "ErkrankungTextLong")] #[serde(rename = "ErkrankungTextLong")]
erkrankung_text_long: String, #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_text_long: Option<String>,
#[serde(rename = "ErkrankungProzedurText")] #[serde(rename = "ErkrankungProzedurText")]
erkrankung_prozedur_text: String, #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_prozedur_text: Option<String>,
#[serde(rename = "ErkrankungSummary")] #[serde(rename = "ErkrankungSummary")]
erkrankung_summary: String, #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_summary: Option<String>,
#[serde(rename = "ErkrankungBigSummary")] #[serde(rename = "ErkrankungBigSummary")]
erkrankung_big_summary: String, #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_big_summary: Option<String>,
#[serde(rename = "Kontext")] #[serde(rename = "Kontext")]
kontext: String, kontext: String,
#[serde(rename = "Datenart")]
#[serde(skip_serializing_if = "Option::is_none")]
datenart: Option<String>,
#[serde(rename = "TudokReadonly")] #[serde(rename = "TudokReadonly")]
tudok_readonly: bool, tudok_readonly: bool,
#[serde(rename = "VitalstatusRelevant")] #[serde(rename = "VitalstatusRelevant")]
@@ -138,6 +148,9 @@ pub struct DataForm {
guid: String, guid: String,
#[serde(rename = "Revision")] #[serde(rename = "Revision")]
revision: u16, revision: u16,
#[serde(rename = "VerknuepftGUID")]
#[serde(skip_serializing_if = "Option::is_none")]
verknuepft_guid: Option<String>,
#[serde(rename = "SeitenzahlSichtbar")] #[serde(rename = "SeitenzahlSichtbar")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
seitenanzahl_sichtbar: Option<bool>, seitenanzahl_sichtbar: Option<bool>,
@@ -148,12 +161,15 @@ pub struct DataForm {
#[serde(rename = "Haeufigkeiten")] #[serde(rename = "Haeufigkeiten")]
haeufigkeiten: Haeufigkeiten, haeufigkeiten: Haeufigkeiten,
#[serde(rename = "Kennzahlen")] #[serde(rename = "Kennzahlen")]
kennzahlen: String, kennzahlen: Kennzahlen,
#[serde(rename = "Ordner")] #[serde(rename = "Ordner")]
ordner: Ordner, ordner: Ordner,
#[serde(rename = "MenuCategory")] #[serde(rename = "MenuCategory")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
menu_category: Option<MenuCategory>, menu_category: Option<MenuCategory>,
#[serde(rename = "PunkteKategorien")]
#[serde(skip_serializing_if = "Option::is_none")]
punkte_kategorien: Option<PunkteKategorien>,
#[serde(rename = "Ansichten")] #[serde(rename = "Ansichten")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
ansichten: Option<Ansichten>, ansichten: Option<Ansichten>,
@@ -369,6 +385,30 @@ impl FolderContent for DataForm {
} }
} }
impl Checkable for DataForm {
fn check(&self) -> Vec<CheckNotice> {
if self
.entries
.entry
.iter()
.filter(|entry| entry.procedure_date_status != "none")
.count()
== 0
{
return vec![ErrorWithCode {
code: "2023-0002".to_string(),
description: format!(
"Formular '{}' hat keine Angabe zum Prozedurdatum",
self.name
),
line: None,
example: None,
}];
}
vec![]
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct DataCatalogues { pub struct DataCatalogues {
@@ -437,6 +477,9 @@ pub struct Entry {
grafik_ausrichtung: Option<String>, grafik_ausrichtung: Option<String>,
#[serde(rename = "Mandatory")] #[serde(rename = "Mandatory")]
mandatory: String, mandatory: String,
#[serde(rename = "Datenart", default)]
#[serde(skip_serializing_if = "Option::is_none")]
datenart: Option<String>,
#[serde(rename = "Filter")] #[serde(rename = "Filter")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
filter: Option<Filter>, filter: Option<Filter>,
@@ -456,6 +499,9 @@ pub struct Entry {
#[serde(rename = "AnzeigeAuswahl")] #[serde(rename = "AnzeigeAuswahl")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
anzeige_auswahl: Option<String>, anzeige_auswahl: Option<String>,
#[serde(rename = "Druckvorlage")]
#[serde(skip_serializing_if = "Option::is_none")]
druckvorlage: Option<String>,
#[serde(rename = "VersionFrom")] #[serde(rename = "VersionFrom")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
version_from: Option<String>, version_from: Option<String>,
@@ -463,6 +509,9 @@ pub struct Entry {
speichern: String, speichern: String,
#[serde(rename = "LeerAusblenden")] #[serde(rename = "LeerAusblenden")]
leer_ausblenden: bool, leer_ausblenden: bool,
#[serde(rename = "Inhalt")]
#[serde(skip_serializing_if = "Option::is_none")]
inhalt: Option<String>,
#[serde(rename = "GeschlossenAnzeigen")] #[serde(rename = "GeschlossenAnzeigen")]
geschlossen_anzeigen: bool, geschlossen_anzeigen: bool,
#[serde(rename = "Min")] #[serde(rename = "Min")]
@@ -472,7 +521,8 @@ pub struct Entry {
#[serde(rename = "InUebersichtAnzeigen")] #[serde(rename = "InUebersichtAnzeigen")]
in_uebersicht_anzeigen: bool, in_uebersicht_anzeigen: bool,
#[serde(rename = "Hinweis")] #[serde(rename = "Hinweis")]
hinweis: String, #[serde(skip_serializing_if = "Option::is_none")]
hinweis: Option<String>,
#[serde(rename = "Vorschlagskategorie")] #[serde(rename = "Vorschlagskategorie")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
vorschlagskategorie: Option<String>, vorschlagskategorie: Option<String>,
@@ -544,6 +594,12 @@ pub struct Entry {
in_auswertung: bool, in_auswertung: bool,
#[serde(rename = "InAuswertungGraph")] #[serde(rename = "InAuswertungGraph")]
in_auswertung_graph: bool, in_auswertung_graph: bool,
#[serde(rename = "FragebogenItemNummer")]
#[serde(skip_serializing_if = "Option::is_none")]
fragebogen_item_nummer: Option<u8>,
#[serde(rename = "Score")]
#[serde(skip_serializing_if = "Option::is_none")]
score: Option<String>,
#[serde(rename = "AlignmentPatModul")] #[serde(rename = "AlignmentPatModul")]
alignment_pat_modul: String, alignment_pat_modul: String,
#[serde(rename = "DirectionPatModul")] #[serde(rename = "DirectionPatModul")]

View File

@@ -27,9 +27,9 @@ use std::collections::hash_map::DefaultHasher;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use crate::model::requirements::Requires;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::model::requirements::Requires;
use crate::profile::{FormField, FormReference, Profile}; use crate::profile::{FormField, FormReference, Profile};
pub mod data_catalogue; pub mod data_catalogue;
@@ -96,11 +96,15 @@ pub struct Ansicht {
#[serde(rename = "Konfiguration")] #[serde(rename = "Konfiguration")]
konfiguration: String, konfiguration: String,
#[serde(rename = "DataForm")] #[serde(rename = "DataForm")]
data_form: String, #[serde(skip_serializing_if = "Option::is_none")]
data_form: Option<String>,
#[serde(rename = "DataCatalogue")] #[serde(rename = "DataCatalogue")]
data_catalogue: String, data_catalogue: String,
#[serde(rename = "TypAuswahl")] #[serde(rename = "TypAuswahl")]
typ_auswahl: String, typ_auswahl: String,
#[serde(rename = "PersonenstammKontext", default)]
#[serde(skip_serializing_if = "Option::is_none")]
personenstamm_kontext: Option<String>,
#[serde(rename = "Suche")] #[serde(rename = "Suche")]
suche: bool, suche: bool,
#[serde(rename = "SID")] #[serde(rename = "SID")]
@@ -131,6 +135,66 @@ pub struct MenuCategory {
column: String, column: String,
} }
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct PunkteKategorien {
#[serde(rename = "PunkteKategorie", default)]
punkte_kategorie: Vec<PunkteKategorie>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct PunkteKategorie {
#[serde(rename = "Name")]
name: String,
#[serde(rename = "Beschreibung")]
beschreibung: String,
#[serde(rename = "MaxLeerwerte")]
max_leerwerte: u16,
#[serde(rename = "Berechnung")]
berechnung: String,
#[serde(rename = "Felder")]
#[serde(skip_serializing_if = "Option::is_none")]
felder: Option<Felder>,
#[serde(rename = "Vergleichswerttabellen")]
vergleichswerttabellen: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Felder {
#[serde(rename = "Feld", default)]
feld: Vec<Feld>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Feld {
#[serde(rename = "DataFormEntryName")]
data_form_entry_name: String,
#[serde(rename = "ManuellePunkte")]
manuelle_punkte: bool,
#[serde(rename = "Werte")]
#[serde(skip_serializing_if = "Option::is_none")]
werte: Option<FeldWerte>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct FeldWerte {
#[serde(rename = "Wert", default)]
wert: Vec<FeldWert>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct FeldWert {
#[serde(rename = "Wert")]
wert: String,
#[serde(rename = "Punkte")]
punkte: String,
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Filter { pub struct Filter {
@@ -189,8 +253,12 @@ pub struct Haeufigkeit {
taeglich_aktualisieren: bool, taeglich_aktualisieren: bool,
#[serde(rename = "Typ")] #[serde(rename = "Typ")]
typ: String, typ: String,
#[serde(rename = "NichtBerechnen")]
#[serde(skip_serializing_if = "Option::is_none")]
nicht_berechnen: Option<String>,
#[serde(rename = "TabellenName")] #[serde(rename = "TabellenName")]
tabellen_name: String, #[serde(skip_serializing_if = "Option::is_none")]
tabellen_name: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -214,6 +282,32 @@ pub struct Ordner {
parent_order: Option<Box<Ordner>>, parent_order: Option<Box<Ordner>>,
} }
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Kennzahlen {
#[serde(rename = "Kennzahl", default)]
kennzahl: Vec<Kennzahl>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Kennzahl {
#[serde(rename = "Name")]
name: String,
#[serde(rename = "Nummer")]
nummer: String,
#[serde(rename = "Beschreibung")]
beschreibung: String,
#[serde(rename = "Notiz")]
notiz: String,
#[serde(rename = "Vorgabe")]
vorgabe: String,
#[serde(rename = "Haeufigkeitenzaehler")]
haeufigkeitenzaehler: String,
#[serde(rename = "Haeufigkeitennenner")]
haeufigkeitennenner: String,
}
fn apply_profile_to_form_entry<E>(entry: &mut E, form_reference: &FormReference) fn apply_profile_to_form_entry<E>(entry: &mut E, form_reference: &FormReference)
where where
E: FormEntry, E: FormEntry,

View File

@@ -30,10 +30,11 @@ use console::style;
use quick_xml::de::from_str; use quick_xml::de::from_str;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::checks::{CheckNotice, Checkable};
use crate::model::data_catalogue::DataCatalogue; use crate::model::data_catalogue::DataCatalogue;
use crate::model::data_form::DataForm; use crate::model::data_form::DataForm;
use crate::model::property_catalogue::PropertyCatalogue; use crate::model::property_catalogue::PropertyCatalogue;
use crate::model::requirements::Requires; use crate::model::requirements::{Requirement, Requires};
use crate::model::unterformular::Unterformular; use crate::model::unterformular::Unterformular;
use crate::model::{Comparable, FolderContent, FormEntryContainer, Listable, Sortable}; use crate::model::{Comparable, FolderContent, FormEntryContainer, Listable, Sortable};
use crate::profile::Profile; use crate::profile::Profile;
@@ -409,6 +410,89 @@ impl FromStr for OnkostarEditor {
} }
} }
impl Checkable for OnkostarEditor {
fn check(&self) -> Vec<CheckNotice> {
// Inner form checks
let mut result = self
.editor
.data_form
.iter()
.flat_map(|entity| entity.check())
.collect::<Vec<_>>();
let other = &mut self
.editor
.unterformular
.iter()
.flat_map(|entity| entity.check())
.collect::<Vec<_>>();
result.append(other);
// Check requirements
let mut requirement_checked_forms = vec![];
fn requirement_error(
form: &impl Comparable,
item: &impl Comparable,
t: &str,
) -> CheckNotice {
CheckNotice::ErrorWithCode {
code: "2023-0004".to_string(),
description: format!(
"'{}' hat einen Verweis auf zuvor nicht definiertes {t} '{}' (OSTARSUPP-13212)",
form.get_name(),
item.get_name()
),
line: None,
example: None,
}
}
self.editor.unterformular.iter().for_each(|form| {
requirement_checked_forms.push(form.get_name());
form.get_required_entries(self)
.iter()
.for_each(|entry| match entry {
Requirement::DataFormReference(&ref item) => {
if !requirement_checked_forms.contains(&item.get_name()) {
result.push(requirement_error(form, item, "Formular"))
}
}
Requirement::UnterformularReference(&ref item) => {
if !requirement_checked_forms.contains(&item.get_name()) {
result.push(requirement_error(form, item, "Unterformular"))
}
}
_ => {}
});
});
self.editor.data_form.iter().for_each(|form| {
requirement_checked_forms.push(form.get_name());
form.get_required_entries(self)
.iter()
.for_each(|entry| match entry {
Requirement::DataFormReference(&ref item) => {
if !requirement_checked_forms.contains(&item.get_name()) {
result.push(requirement_error(form, item, "Formular"))
}
}
Requirement::UnterformularReference(&ref item) => {
if !requirement_checked_forms.contains(&item.get_name()) {
result.push(requirement_error(form, item, "Unterformular"))
}
}
_ => {}
});
});
result
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct InfoXML { pub struct InfoXML {

View File

@@ -127,12 +127,12 @@ pub struct Version {
#[serde(rename = "Revision")] #[serde(rename = "Revision")]
revision: u16, revision: u16,
#[serde(rename = "Entries")] #[serde(rename = "Entries")]
entries: VersionEntries, entries: Option<VersionEntries>,
#[serde(rename = "Abbildung")] #[serde(rename = "Abbildung")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
abbildung: Option<Vec<Abbildung>>, abbildung: Option<Vec<Abbildung>>,
#[serde(rename = "Categories")] #[serde(rename = "Categories")]
categories: Categories, categories: Option<Categories>,
} }
impl Sortable for Version { impl Sortable for Version {
@@ -151,19 +151,23 @@ impl Sortable for Version {
}); });
} }
self.entries if let Some(ref mut entries) = self.entries {
.content entries
.sort_unstable_by_key(|item| item.sorting_key()); .content
self.entries.content.iter_mut().for_each(|item| { .sort_unstable_by_key(|item| item.sorting_key());
item.sorted(); entries.content.iter_mut().for_each(|item| {
}); item.sorted();
});
}
self.categories if let Some(ref mut categories) = self.categories {
.content categories
.sort_unstable_by_key(|item| item.sorting_key()); .content
self.categories.content.iter_mut().for_each(|item| { .sort_unstable_by_key(|item| item.sorting_key());
item.sorted(); categories.content.iter_mut().for_each(|item| {
}); item.sorted();
});
}
self self
} }
@@ -184,13 +188,16 @@ pub struct VersionEntry {
#[serde(rename = "ShortDescription")] #[serde(rename = "ShortDescription")]
short_description: String, short_description: String,
#[serde(rename = "Description")] #[serde(rename = "Description")]
description: String, description: Option<String>,
#[serde(rename = "Synonyms", default)] #[serde(rename = "Synonyms", default)]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
synonyms: Option<String>, synonyms: Option<String>,
#[serde(rename = "Note", default)] #[serde(rename = "Note", default)]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
note: Option<String>, note: Option<String>,
#[serde(rename = "Type", default)]
#[serde(skip_serializing_if = "Option::is_none")]
type_: Option<String>,
#[serde(rename = "Position")] #[serde(rename = "Position")]
position: String, position: String,
} }
@@ -331,8 +338,9 @@ pub struct AbbildungEntry {
#[serde(rename = "Synonyms")] #[serde(rename = "Synonyms")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
synonyms: Option<String>, synonyms: Option<String>,
#[serde(rename = "Note")] #[serde(rename = "Note", default)]
note: String, #[serde(skip_serializing_if = "Option::is_none")]
note: Option<String>,
#[serde(rename = "Position")] #[serde(rename = "Position")]
position: String, position: String,
} }

View File

@@ -25,6 +25,8 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::HashSet; use std::collections::HashSet;
use crate::checks::CheckNotice::ErrorWithCode;
use crate::checks::{CheckNotice, Checkable};
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -32,8 +34,8 @@ use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires}; use crate::model::requirements::{Requirement, Requires};
use crate::model::{ use crate::model::{
apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries, apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries,
Filter, FolderContent, FormEntry, FormEntryContainer, Listable, MenuCategory, Filter, FolderContent, FormEntry, FormEntryContainer, Kennzahlen, Listable, MenuCategory,
PlausibilityRules, RefEntries, Script, Sortable, PlausibilityRules, PunkteKategorien, RefEntries, Script, Sortable,
}; };
use crate::model::{Haeufigkeiten, Ordner}; use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile; use crate::profile::Profile;
@@ -80,7 +82,7 @@ pub struct Unterformular {
#[serde(rename = "EmailTemplate")] #[serde(rename = "EmailTemplate")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
mail_template: Option<String>, mail_template: Option<String>,
#[serde(rename = "ErkrankungText")] #[serde(rename = "ErkrankungText", default)]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
erkrankung_text: Option<String>, erkrankung_text: Option<String>,
#[serde(rename = "ErkrankungTextLong")] #[serde(rename = "ErkrankungTextLong")]
@@ -97,6 +99,9 @@ pub struct Unterformular {
erkrankung_big_summary: Option<String>, erkrankung_big_summary: Option<String>,
#[serde(rename = "Kontext")] #[serde(rename = "Kontext")]
kontext: String, kontext: String,
#[serde(rename = "Datenart")]
#[serde(skip_serializing_if = "Option::is_none")]
datenart: Option<String>,
#[serde(rename = "TudokReadonly")] #[serde(rename = "TudokReadonly")]
tudok_readonly: bool, tudok_readonly: bool,
#[serde(rename = "VitalstatusRelevant")] #[serde(rename = "VitalstatusRelevant")]
@@ -159,12 +164,15 @@ pub struct Unterformular {
#[serde(rename = "Haeufigkeiten")] #[serde(rename = "Haeufigkeiten")]
haeufigkeiten: Haeufigkeiten, haeufigkeiten: Haeufigkeiten,
#[serde(rename = "Kennzahlen")] #[serde(rename = "Kennzahlen")]
kennzahlen: String, kennzahlen: Kennzahlen,
#[serde(rename = "Ordner")] #[serde(rename = "Ordner")]
ordner: Ordner, ordner: Ordner,
#[serde(rename = "MenuCategory")] #[serde(rename = "MenuCategory")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
menu_category: Option<MenuCategory>, menu_category: Option<MenuCategory>,
#[serde(rename = "PunkteKategorien")]
#[serde(skip_serializing_if = "Option::is_none")]
punkte_kategorien: Option<PunkteKategorien>,
#[serde(rename = "Ansichten")] #[serde(rename = "Ansichten")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
ansichten: Option<Ansichten>, ansichten: Option<Ansichten>,
@@ -374,6 +382,24 @@ impl FolderContent for Unterformular {
} }
} }
impl Checkable for Unterformular {
fn check(&self) -> Vec<CheckNotice> {
if self.hat_unterformulare {
return vec![ErrorWithCode {
code: "2023-0001".to_string(),
description: format!(
"Unterformular '{}' mit Markierung 'hat Unterformulare'",
self.name
),
line: None,
example: None,
}];
}
vec![]
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct DataCatalogues { pub struct DataCatalogues {
@@ -442,6 +468,9 @@ pub struct Entry {
grafik_ausrichtung: Option<String>, grafik_ausrichtung: Option<String>,
#[serde(rename = "Mandatory")] #[serde(rename = "Mandatory")]
mandatory: String, mandatory: String,
#[serde(rename = "Datenart", default)]
#[serde(skip_serializing_if = "Option::is_none")]
datenart: Option<String>,
#[serde(rename = "Filter")] #[serde(rename = "Filter")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
filter: Option<Filter>, filter: Option<Filter>,
@@ -461,6 +490,9 @@ pub struct Entry {
#[serde(rename = "AnzeigeAuswahl")] #[serde(rename = "AnzeigeAuswahl")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
anzeige_auswahl: Option<String>, anzeige_auswahl: Option<String>,
#[serde(rename = "Druckvorlage")]
#[serde(skip_serializing_if = "Option::is_none")]
druckvorlage: Option<String>,
#[serde(rename = "VersionFrom")] #[serde(rename = "VersionFrom")]
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
version_from: Option<String>, version_from: Option<String>,
@@ -468,6 +500,9 @@ pub struct Entry {
speichern: String, speichern: String,
#[serde(rename = "LeerAusblenden")] #[serde(rename = "LeerAusblenden")]
leer_ausblenden: bool, leer_ausblenden: bool,
#[serde(rename = "Inhalt")]
#[serde(skip_serializing_if = "Option::is_none")]
inhalt: Option<String>,
#[serde(rename = "GeschlossenAnzeigen")] #[serde(rename = "GeschlossenAnzeigen")]
geschlossen_anzeigen: bool, geschlossen_anzeigen: bool,
#[serde(rename = "Min")] #[serde(rename = "Min")]
@@ -550,6 +585,12 @@ pub struct Entry {
in_auswertung: bool, in_auswertung: bool,
#[serde(rename = "InAuswertungGraph")] #[serde(rename = "InAuswertungGraph")]
in_auswertung_graph: bool, in_auswertung_graph: bool,
#[serde(rename = "FragebogenItemNummer")]
#[serde(skip_serializing_if = "Option::is_none")]
fragebogen_item_nummer: Option<u8>,
#[serde(rename = "Score")]
#[serde(skip_serializing_if = "Option::is_none")]
score: Option<String>,
#[serde(rename = "AlignmentPatModul")] #[serde(rename = "AlignmentPatModul")]
alignment_pat_modul: String, alignment_pat_modul: String,
#[serde(rename = "DirectionPatModul")] #[serde(rename = "DirectionPatModul")]

View File

@@ -34,6 +34,19 @@ pub struct Profile {
pub forms: Vec<Form>, pub forms: Vec<Form>,
} }
impl Profile {
pub fn embedded_profile(name: &str) -> Result<Profile, String> {
let s = match name {
"UKM" => include_str!("../examples/dnpm-ukm.yml"),
"UKW" => include_str!("../examples/dnpm-ukw.yml"),
"UMG" => include_str!("../examples/dnpm-umg.yml"),
_ => return Err(format!("Not an embedded profile: '{name}'")),
};
Profile::from_str(s)
}
}
impl FromStr for Profile { impl FromStr for Profile {
type Err = String; type Err = String;

View File

@@ -24,6 +24,7 @@
use console::style; use console::style;
use deob::deobfuscate; use deob::deobfuscate;
use std::path::Path;
use std::{fs, io}; use std::{fs, io};
macro_rules! started { macro_rules! started {
@@ -48,11 +49,9 @@ macro_rules! error {
}; };
} }
pub fn unzip_osb(path: &str) { pub fn unzip_osb_using_password(path: &str, dir: &str, password: &str) {
println!("Entpacke OSB-Datei {}\n", style(path).yellow()); println!("Entpacke OSB-Datei {}\n", style(path).yellow());
let pw = deobfuscate(env!("OSB_KEY").trim());
let file = match fs::File::open(path) { let file = match fs::File::open(path) {
Ok(file) => file, Ok(file) => file,
Err(err) => { Err(err) => {
@@ -78,7 +77,7 @@ pub fn unzip_osb(path: &str) {
}; };
for i in 0..archive.len() { for i in 0..archive.len() {
let mut file = if let Ok(Ok(file)) = archive.by_index_decrypt(i, pw.as_bytes()) { let mut file = if let Ok(Ok(file)) = archive.by_index_decrypt(i, password.as_bytes()) {
file file
} else { } else {
println!( println!(
@@ -89,7 +88,7 @@ pub fn unzip_osb(path: &str) {
}; };
let outpath = match file.enclosed_name() { let outpath = match file.enclosed_name() {
Some(path) => path.to_owned(), Some(path) => Path::new(dir).join(path.to_owned()),
None => continue, None => continue,
}; };
@@ -130,3 +129,7 @@ pub fn unzip_osb(path: &str) {
} }
} }
} }
pub fn unzip_osb(path: &str, dir: &str) {
unzip_osb_using_password(path, dir, deobfuscate(env!("OSB_KEY").trim()).as_str());
}