diff --git a/.gitignore b/.gitignore index bcd5559..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ /target - -.DS_Store diff --git a/BookForge.toml b/BookForge.toml index 0ac7cc8..3c2268e 100644 --- a/BookForge.toml +++ b/BookForge.toml @@ -1,6 +1,4 @@ database_path = "" -locale = "fr" -base_url = "" [listener] port = 8000 diff --git a/Cargo.lock b/Cargo.lock index ef09c66..232c525 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,15 +99,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "arc-swap" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" -dependencies = [ - "rustversion", -] - [[package]] name = "arrayvec" version = "0.7.6" @@ -296,12 +287,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "base62" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adf9755786e27479693dedd3271691a92b5e242ab139cacb9fb8e7fb5381111" - [[package]] name = "base64" version = "0.22.1" @@ -337,12 +322,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -381,11 +360,9 @@ dependencies = [ "askama_web", "axum", "camino", - "csv", "dirs", "log", "pretty_env_logger", - "rust-i18n", "sea-orm", "sea-orm-migration", "serde", @@ -393,7 +370,7 @@ dependencies = [ "snafu", "static-serve", "tokio", - "toml 0.9.11+spec-1.1.0", + "toml", "xdg", ] @@ -420,16 +397,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "bstr" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "bumpalo" version = "3.19.1" @@ -615,25 +582,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-queue" version = "0.3.12" @@ -659,27 +607,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "csv" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde_core", -] - -[[package]] -name = "csv-core" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" -dependencies = [ - "memchr", -] - [[package]] name = "darling" version = "0.20.11" @@ -1069,30 +996,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "globset" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -1399,22 +1302,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "ignore" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - [[package]] name = "indexmap" version = "1.9.3" @@ -1475,15 +1362,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -1546,7 +1424,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags", "libc", "redox_syscall 0.7.0", ] @@ -1651,15 +1529,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "normpath" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "num-bigint" version = "0.4.6" @@ -1915,7 +1784,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.10+spec-1.0.0", + "toml_edit", ] [[package]] @@ -2039,7 +1908,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -2048,7 +1917,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -2169,60 +2038,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rust-i18n" -version = "3.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda2551fdfaf6cc5ee283adc15e157047b92ae6535cf80f6d4962d05717dc332" -dependencies = [ - "globwalk", - "once_cell", - "regex", - "rust-i18n-macro", - "rust-i18n-support", - "smallvec", -] - -[[package]] -name = "rust-i18n-macro" -version = "3.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22baf7d7f56656d23ebe24f6bb57a5d40d2bce2a5f1c503e692b5b2fa450f965" -dependencies = [ - "glob", - "once_cell", - "proc-macro2", - "quote", - "rust-i18n-support", - "serde", - "serde_json", - "serde_yaml", - "syn 2.0.114", -] - -[[package]] -name = "rust-i18n-support" -version = "3.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940ed4f52bba4c0152056d771e563b7133ad9607d4384af016a134b58d758f19" -dependencies = [ - "arc-swap", - "base62", - "globwalk", - "itertools 0.11.0", - "lazy_static", - "normpath", - "once_cell", - "proc-macro2", - "regex", - "serde", - "serde_json", - "serde_yaml", - "siphasher", - "toml 0.8.23", - "triomphe", -] - [[package]] name = "rust_decimal" version = "1.40.0" @@ -2266,15 +2081,6 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "schemars" version = "0.9.0" @@ -2330,7 +2136,7 @@ dependencies = [ "chrono", "derive_more", "futures-util", - "itertools 0.14.0", + "itertools", "log", "ouroboros", "pgvector", @@ -2534,15 +2340,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - [[package]] name = "serde_spanned" version = "1.0.4" @@ -2595,19 +2392,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap 2.13.0", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha1" version = "0.10.6" @@ -2667,12 +2451,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" -[[package]] -name = "siphasher" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" - [[package]] name = "slab" version = "0.4.11" @@ -2835,7 +2613,7 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", "base64", - "bitflags 2.10.0", + "bitflags", "byteorder", "bytes", "chrono", @@ -2881,7 +2659,7 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", "base64", - "bitflags 2.10.0", + "bitflags", "byteorder", "chrono", "crc", @@ -3185,18 +2963,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - [[package]] name = "toml" version = "0.9.11+spec-1.1.0" @@ -3205,22 +2971,13 @@ checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ "indexmap 2.13.0", "serde_core", - "serde_spanned 1.0.4", - "toml_datetime 0.7.5+spec-1.1.0", + "serde_spanned", + "toml_datetime", "toml_parser", "toml_writer", "winnow", ] -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - [[package]] name = "toml_datetime" version = "0.7.5+spec-1.1.0" @@ -3230,20 +2987,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.13.0", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_write", - "winnow", -] - [[package]] name = "toml_edit" version = "0.23.10+spec-1.0.0" @@ -3251,7 +2994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ "indexmap 2.13.0", - "toml_datetime 0.7.5+spec-1.1.0", + "toml_datetime", "toml_parser", "winnow", ] @@ -3265,12 +3008,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - [[package]] name = "toml_writer" version = "1.0.6+spec-1.1.0" @@ -3352,17 +3089,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "triomphe" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" -dependencies = [ - "arc-swap", - "serde", - "stable_deref_trait", -] - [[package]] name = "typenum" version = "1.19.0" @@ -3408,12 +3134,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "url" version = "2.5.8" @@ -3461,16 +3181,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 83d8600..145fe87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,5 +31,3 @@ pretty_env_logger = "0.5.0" # custom logger log = "0.4.29" serde_with = "3.16.1" -csv = "1.4.0" -rust-i18n = "3.1.5" diff --git a/assets/css/fork-awesome.min.css b/assets/css/fork-awesome.min.css deleted file mode 100755 index fd154dc..0000000 --- a/assets/css/fork-awesome.min.css +++ /dev/null @@ -1,12 +0,0 @@ -/*! -Fork Awesome 1.2.0 -License - https://forkaweso.me/Fork-Awesome/license - -Copyright 2018 Dave Gandy & Fork Awesome - -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. - */@font-face{font-family:ForkAwesome;src:url(../fonts/forkawesome-webfont.eot?v=1.2.0);src:url(../fonts/forkawesome-webfont.eot?#iefix&v=1.2.0) format('embedded-opentype'),url(../fonts/forkawesome-webfont.woff2?v=1.2.0) format('woff2'),url(../fonts/forkawesome-webfont.woff?v=1.2.0) format('woff'),url(../fonts/forkawesome-webfont.ttf?v=1.2.0) format('truetype'),url(../fonts/forkawesome-webfont.svg?v=1.2.0#forkawesomeregular) format('svg');font-weight:400;font-style:normal;font-display:block}.fa{display:inline-block;font:normal normal normal 14px/1 ForkAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1,1);-ms-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-rotate-90{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-close:before,.fa-remove:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-cog:before,.fa-gear:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-repeat:before,.fa-rotate-right:before{content:"\f01e"}.fa-refresh:before,.fa-sync:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before,.fa-video:before{content:"\f03d"}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-exclamation-triangle:before,.fa-warning:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-cogs:before,.fa-gears:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell-o:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-globe-e:before{content:"\f304"}.fa-globe-w:before{content:"\f305"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-community:before,.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-floppy-o:before,.fa-save:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus-g:before,.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-sort:before,.fa-unsorted:before{content:"\f0dc"}.fa-sort-desc:before,.fa-sort-down:before{content:"\f0dd"}.fa-sort-asc:before,.fa-sort-up:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-gavel:before,.fa-legal:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-bolt:before,.fa-flash:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-clipboard:before,.fa-paste:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before,.fa-utensils:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-chain-broken:before,.fa-unlink:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:"\f150"}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:"\f151"}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:"\f152"}.fa-eur:before,.fa-euro:before{content:"\f153"}.fa-gbp:before,.fa-pound:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-inr:before,.fa-rupee:before{content:"\f156"}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:"\f157"}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:"\f158"}.fa-krw:before,.fa-won:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before,.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-desc:before,.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-asc:before,.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-desc:before,.fa-sort-amount-up:before{content:"\f161"}.fa-sort-numeric-asc:before,.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-desc:before,.fa-sort-numeric-up:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-try:before,.fa-turkish-lira:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-bank:before,.fa-institution:before,.fa-university:before{content:"\f19c"}.fa-graduation-cap:before,.fa-mortar-board:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before,.fa-utensil-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:"\f1c5"}.fa-file-archive-o:before,.fa-file-zip-o:before{content:"\f1c6"}.fa-file-audio-o:before,.fa-file-sound-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:"\f1d0"}.fa-empire:before,.fa-ge:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-paper-plane:before,.fa-send:before{content:"\f1d8"}.fa-paper-plane-o:before,.fa-send-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before,.fa-heading:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before,.fa-closed-captioning:before{content:"\f20a"}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before,.fa-gem:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-bed:before,.fa-hotel:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-medium-square:before{content:"\f2f8"}.fa-y-combinator:before,.fa-yc:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-television:before,.fa-tv:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo-v:before,.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-phone-volume:before,.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:"\f2a3"}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-sign-language:before,.fa-signing:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-address-card:before,.fa-vcard:before{content:"\f2bb"}.fa-address-card-o:before,.fa-vcard-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.fa-mastodon:before{content:"\f2e1"}.fa-mastodon-alt:before{content:"\f2e2"}.fa-fork-awesome:before,.fa-fork-circle:before{content:"\f2e3"}.fa-peertube:before{content:"\f2e4"}.fa-diaspora:before{content:"\f2e5"}.fa-friendica:before{content:"\f2e6"}.fa-gnu-social:before{content:"\f2e7"}.fa-liberapay-square:before{content:"\f2e8"}.fa-liberapay:before{content:"\f2e9"}.fa-scuttlebutt:before,.fa-ssb:before{content:"\f2ea"}.fa-hubzilla:before{content:"\f2eb"}.fa-social-home:before{content:"\f2ec"}.fa-artstation:before{content:"\f2ed"}.fa-discord:before{content:"\f2ee"}.fa-discord-alt:before{content:"\f2ef"}.fa-patreon:before{content:"\f2f0"}.fa-snowdrift:before{content:"\f2f1"}.fa-activitypub:before{content:"\f2f2"}.fa-ethereum:before{content:"\f2f3"}.fa-keybase:before{content:"\f2f4"}.fa-shaarli:before{content:"\f2f5"}.fa-shaarli-o:before{content:"\f2f6"}.fa-cut-key:before,.fa-key-modern:before{content:"\f2f7"}.fa-xmpp:before{content:"\f2f9"}.fa-archive-org:before{content:"\f2fc"}.fa-freedombox:before{content:"\f2fd"}.fa-facebook-messenger:before{content:"\f2fe"}.fa-debian:before{content:"\f2ff"}.fa-mastodon-square:before{content:"\f300"}.fa-tipeee:before{content:"\f301"}.fa-react:before{content:"\f302"}.fa-dogmazic:before{content:"\f303"}.fa-zotero:before{content:"\f309"}.fa-nodejs:before{content:"\f308"}.fa-nextcloud:before{content:"\f306"}.fa-nextcloud-square:before{content:"\f307"}.fa-hackaday:before{content:"\f30a"}.fa-laravel:before{content:"\f30b"}.fa-signalapp:before{content:"\f30c"}.fa-gnupg:before{content:"\f30d"}.fa-php:before{content:"\f30e"}.fa-ffmpeg:before{content:"\f30f"}.fa-joplin:before{content:"\f310"}.fa-syncthing:before{content:"\f311"}.fa-inkscape:before{content:"\f312"}.fa-matrix-org:before{content:"\f313"}.fa-pixelfed:before{content:"\f314"}.fa-bootstrap:before{content:"\f315"}.fa-dev-to:before{content:"\f316"}.fa-hashnode:before{content:"\f317"}.fa-jirafeau:before{content:"\f318"}.fa-emby:before{content:"\f319"}.fa-wikidata:before{content:"\f31a"}.fa-gimp:before{content:"\f31b"}.fa-c:before{content:"\f31c"}.fa-digitalocean:before{content:"\f31d"}.fa-att:before{content:"\f31e"}.fa-gitea:before{content:"\f31f"}.fa-file-epub:before{content:"\f321"}.fa-python:before{content:"\f322"}.fa-archlinux:before{content:"\f323"}.fa-pleroma:before{content:"\f324"}.fa-unsplash:before{content:"\f325"}.fa-hackster:before{content:"\f326"}.fa-spell-check:before{content:"\f327"}.fa-moon:before{content:"\f328"}.fa-sun:before{content:"\f329"}.fa-f-droid:before{content:"\f32a"}.fa-biometric:before{content:"\f32b"}.fa-wire:before{content:"\f32c"}.fa-tor-onion:before{content:"\f32e"}.fa-volume-mute:before{content:"\f32f"}.fa-bell-ringing:before{content:"\f32d"}.fa-bell-ringing-o:before{content:"\f330"}.fa-hal:before{content:"\f333"}.fa-jupyter:before{content:"\f335"}.fa-julia:before{content:"\f334"}.fa-classicpress:before{content:"\f331"}.fa-classicpress-circle:before{content:"\f332"}.fa-open-collective:before{content:"\f336"}.fa-orcid:before{content:"\f337"}.fa-researchgate:before{content:"\f338"}.fa-funkwhale:before{content:"\f339"}.fa-askfm:before{content:"\f33a"}.fa-blockstack:before{content:"\f33b"}.fa-boardgamegeek:before{content:"\f33c"}.fa-bunny:before{content:"\f35f"}.fa-buymeacoffee:before{content:"\f33d"}.fa-cc-by:before{content:"\f33e"}.fa-cc-cc:before,.fa-creative-commons-alt:before{content:"\f33f"}.fa-cc-nc-eu:before{content:"\f341"}.fa-cc-nc-jp:before{content:"\f342"}.fa-cc-nc:before{content:"\f340"}.fa-cc-nd:before{content:"\f343"}.fa-cc-pd:before{content:"\f344"}.fa-cc-remix:before{content:"\f345"}.fa-cc-sa:before{content:"\f346"}.fa-cc-share:before{content:"\f347"}.fa-cc-zero:before{content:"\f348"}.fa-conway-glider:before,.fa-conway-hacker:before{content:"\f349"}.fa-csharp:before{content:"\f34a"}.fa-email-bulk:before{content:"\f34b"}.fa-email-bulk-o:before{content:"\f34c"}.fa-gnu:before{content:"\f34d"}.fa-google-play:before{content:"\f34e"}.fa-heroku:before{content:"\f34f"}.fa-hassio:before,.fa-home-assistant:before{content:"\f350"}.fa-java:before{content:"\f351"}.fa-mariadb:before{content:"\f352"}.fa-markdown:before{content:"\f353"}.fa-mysql:before{content:"\f354"}.fa-nordcast:before{content:"\f355"}.fa-plume:before{content:"\f356"}.fa-postgresql:before{content:"\f357"}.fa-sass-alt:before{content:"\f359"}.fa-sass:before{content:"\f358"}.fa-skate:before{content:"\f35a"}.fa-sketchfab:before{content:"\f35b"}.fa-tex:before{content:"\f35c"}.fa-textpattern:before{content:"\f35d"}.fa-unity:before{content:"\f35e"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}/*# sourceMappingURL=fork-awesome.min.css.map */ \ No newline at end of file diff --git a/assets/fonts/forkawesome-webfont.woff2 b/assets/fonts/forkawesome-webfont.woff2 deleted file mode 100755 index c96e5bf..0000000 Binary files a/assets/fonts/forkawesome-webfont.woff2 and /dev/null differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png deleted file mode 100644 index 5dbbdbe..0000000 Binary files a/assets/images/favicon.png and /dev/null differ diff --git a/locales/en.yml b/locales/en.yml deleted file mode 100644 index 5e258e0..0000000 --- a/locales/en.yml +++ /dev/null @@ -1,92 +0,0 @@ -_version: 1 -name: "BookForge" - -common: - download: Download - create: Create - edit: Edit - delete: Delete - next: Next - previous: Previous - actions: Actions - search: Search - reset: Reset - show: Show - no_result: No results - close: Close - confirmation: Confirmation - are_you_sure: Are you sure? - -nav: - toggle: Toggle navigation - books: Books - users: Users - -theme: - light: Light - dark: Dark - -user: - attributes: - name: Name - owner_books: Owned books - borrowed_books: Borrowed books - - index: - title_tag: Users list | BookForge - title: All Users - button: Add a user - - edit: - title_tag: Edit user | BookForge - title: Edit - button: Edit user - - new: - title_tag: New user | BookForge - title: New user - button: Create user - -book: - attributes: - title: Title - authors: Author(s) - description: Description - owner: Owner - current_holder: Current holder - comment: Comment - - index: - title_tag: Books list | BookForge - title: All Books - - new: - title_tag: New book | BookForge - title: New Book - button: Create book - button_short: Add book - - edit: - title_tag: Edit book | BookForge - title: Edit book - button: Edit book - - show: - title_tag: Details | BookForge - book_details: Book details - user_details: User details - more_informations: More information - -footer: - message: Made with love & Fuck fascists! - -error: - error_404: - title_tag: Error 404 | BookForge - title: Oops! This page does not exist - subtitle: 404 NOT FOUND - button: Back to home - - generic: - title_tag: Error | BookForge - title: Oops! An error occurred diff --git a/locales/fr.yml b/locales/fr.yml deleted file mode 100644 index 22b0675..0000000 --- a/locales/fr.yml +++ /dev/null @@ -1,77 +0,0 @@ -_version: 1 -name: "BookForge" -common: - download: Télécharger - create: Créer - edit: Modifier - delete: Supprimer - next: Suivant - previous: Précédent - actions: Actions - search: Filtrer - reset: Réini. - show: Voir - no_result: Aucun résultat - close: Fermer - confirmation: Confirmation - are_you_sure: Êtes-vous sûr ? -nav: - toggle: Basculer la navigation - books: Livres - users: Utilisateurs -theme: - light: Light - dark: Dark -user: - attributes: - name: Nom - owner_books: Livres possédés - borrowed_books: Livres empruntés - index: - title_tag: Liste des utilisateur.ice.s | BookForge - title: Tous les utilisateur.ice.s - button: Ajouter un.e utilisateur.ice - edit: - title_tag: Modifier l'utilisateur.ice | BookForge - title: Modifier - button: Modifier l'utilisateur.ice - new: - title_tag: Nouvel utilisateur.ice | BookForge - title: Nouvel utilisateur.ice - button: Créer l'utilisateur.ice -book: - attributes: - title: Titre - authors: Auteur.ice.(s) - description: Description - owner: Propriétaire - current_holder: Détenteur.ice actuel.le - comment: Commentaire - index: - title_tag: Liste des livres | BookForge - title: Tous les livres - new: - title_tag: Nouveau livre | BookForge - title: Nouveau livre - button: Créer le livre - button_short: Ajouter un livre - edit: - title_tag: Modifier le livre | BookForge - title: Modifier le livre - button: Modifier le livre - show: - title_tag: Details | BookForge - book_details: Détails du livre - user_details: Détails de l'utilisateur.ice - more_informations: Plus d'informations -footer: - message: Fait avec amour & Nique les fachos ! -error: - error_404: - title_tag: Erreur 404 | BookForge - title: Oups ! Cette page n'existe pas - subtitle: 404 NOT FOUND - button: Retour à l'accueil - generic: - title_tag: Erreur | BookForge - title: Oups ! Une erreur s'est produite diff --git a/src/lib.rs b/src/lib.rs index 6c3de23..d9a0fa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,9 @@ -use askama::Template; -use askama_web::WebTemplate; use axum::{ Router, - extract::State, routing::{get, post}, }; use static_serve::embed_assets; -use crate::routes::router::Router as InternalRouter; use crate::state::AppState; mod migrations; @@ -15,45 +11,20 @@ mod models; mod routes; pub mod state; -#[macro_use] -extern crate rust_i18n; - -i18n!("locales", fallback = "en", minify_key = true); - pub fn build_app(state: AppState) -> Router { - rust_i18n::set_locale(&state.config.locale); embed_assets!("assets", compress = true); Router::new() .route("/", get(routes::book::index)) - .route("/books/new", get(routes::book::new)) .route("/books", post(routes::book::create)) .route("/books/{id}", get(routes::book::show)) .route("/books/{id}", post(routes::book::update)) .route("/books/{id}/delete", post(routes::book::delete)) .route("/books/{id}/edit", get(routes::book::edit)) - .route("/books/download_csv", get(routes::book::download_csv)) + .route("/books/new", get(routes::book::new)) .route("/users", get(routes::user::index)) - .route("/users/new", get(routes::user::new)) - .route("/users/{id}/edit", get(routes::user::edit)) - .route("/users/{id}", post(routes::user::update)) .route("/users", post(routes::user::create)) - .route("/users/{id}/delete", post(routes::user::delete)) + .route("/users/{id}", post(routes::user::delete)) .nest("/assets", static_router()) - .fallback(error_handler) .with_state(state) } - -#[derive(Template, WebTemplate)] -#[template(path = "404.html")] -struct NotFoundTemplate { - pub router: InternalRouter, -} - -pub async fn error_handler(State(state): State) -> impl axum::response::IntoResponse { - NotFoundTemplate { - router: InternalRouter { - base_path: state.config.base_path, - }, - } -} diff --git a/src/models/book.rs b/src/models/book.rs index b61753a..ea84252 100644 --- a/src/models/book.rs +++ b/src/models/book.rs @@ -70,7 +70,7 @@ impl BookOperator { /// Lists all books matching the optional query filters. /// /// Results are ordered by ID in descending order (newest first). - pub async fn all(&self) -> Result, BookError> { + pub async fn list(&self) -> Result, BookError> { Entity::find() .order_by_desc(Column::Id) .all(&self.state.db) @@ -78,18 +78,7 @@ impl BookOperator { .context(DBSnafu) } - pub async fn all_filtered(&self, query: Option) -> Result, BookError> { - let conditions = Self::filter_conditions(query); - - Entity::find() - .filter(conditions) - .order_by_desc(Column::Id) - .all(&self.state.db) - .await - .context(DBSnafu) - } - - pub async fn all_paginate( + pub async fn list_paginate( &self, page: u64, query: Option, @@ -97,12 +86,29 @@ impl BookOperator { let page = if page > 0 { page } else { 1 }; // keep 1-indexed let page_0indexed = page - 1; // convert for SeaORM (0-based index) - let conditions = Self::filter_conditions(query); + let mut conditions = Condition::all(); + if let Some(book_query) = query { + if let Some(title) = book_query.title { + conditions = conditions.add(Column::Title.contains(&title)); + } + + if let Some(authors) = book_query.authors { + conditions = conditions.add(Column::Authors.contains(&authors)); + } + + if let Some(owner_id) = book_query.owner_id { + conditions = conditions.add(Column::OwnerId.eq(owner_id)); + } + + if let Some(current_holder_id) = book_query.current_holder_id { + conditions = conditions.add(Column::CurrentHolderId.eq(current_holder_id)); + } + } let book_pages = Entity::find() .filter(conditions) .order_by_desc(Column::Id) - .paginate(&self.state.db, 100); + .paginate(&self.state.db, 1); let books = book_pages .fetch_page(page_0indexed) @@ -134,27 +140,6 @@ impl BookOperator { } } - /// Finds vec of book by its Owner - pub async fn find_all_by_owner(&self, owner_id: i32) -> Result, BookError> { - Entity::find() - .filter(Column::OwnerId.eq(owner_id)) - .all(&self.state.db) - .await - .context(DBSnafu) - } - - /// Finds vec of book by its Owner - pub async fn find_all_by_current_holder( - &self, - current_holder_id: i32, - ) -> Result, BookError> { - Entity::find() - .filter(Column::CurrentHolderId.eq(current_holder_id)) - .all(&self.state.db) - .await - .context(DBSnafu) - } - /// Creates a new book from the given form data. pub async fn create(&self, form: BookForm) -> Result { let book = ActiveModel { @@ -203,28 +188,4 @@ impl BookOperator { book.delete(&self.state.db).await.context(DBSnafu) } - - // private - - fn filter_conditions(query: Option) -> Condition { - let mut conditions = Condition::all(); - if let Some(book_query) = query { - if let Some(title) = book_query.title { - conditions = conditions.add(Column::Title.contains(&title)); - } - - if let Some(authors) = book_query.authors { - conditions = conditions.add(Column::Authors.contains(&authors)); - } - - if let Some(owner_id) = book_query.owner_id { - conditions = conditions.add(Column::OwnerId.eq(owner_id)); - } - - if let Some(current_holder_id) = book_query.current_holder_id { - conditions = conditions.add(Column::CurrentHolderId.eq(current_holder_id)); - } - } - return conditions; - } } diff --git a/src/models/user.rs b/src/models/user.rs index 0ce96eb..0311fa4 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -1,11 +1,6 @@ -use crate::models::book; -use crate::routes::book::BookForm; -use crate::routes::user::IndexQuery; use crate::routes::user::UserForm; use crate::state::AppState; -use crate::state::error::UserSnafu; use sea_orm::ActiveValue::Set; -use sea_orm::Condition; use sea_orm::DeleteResult; use sea_orm::entity::prelude::*; use snafu::ResultExt; @@ -41,8 +36,6 @@ pub enum UserError { DB { source: sea_orm::DbErr }, #[snafu(display("User with id {id} not found"))] NotFound { id: i32 }, - #[snafu(display("Book error"))] - Book { source: super::book::BookError }, } #[derive(Debug)] @@ -55,23 +48,10 @@ impl UserOperator { Self { state } } - pub async fn all(&self) -> Result, UserError> { + pub async fn list(&self) -> Result, UserError> { Entity::find().all(&self.state.db).await.context(DBSnafu) } - pub async fn all_filtered(&self, query: IndexQuery) -> Result, UserError> { - let mut conditions = Condition::all(); - if let Some(name) = query.name { - conditions = conditions.add(Column::Name.contains(name)) - } - - Entity::find() - .filter(conditions) - .all(&self.state.db) - .await - .context(DBSnafu) - } - pub async fn find_by_id(&self, id: i32) -> Result { let user: Option = Entity::find_by_id(id) .one(&self.state.db) @@ -94,60 +74,7 @@ impl UserOperator { user.insert(&self.state.db).await.context(DBSnafu) } - pub async fn update(&self, id: i32, form: UserForm) -> Result { - let user_by_id = Self::find_by_id(&self, id).await.context(UserSnafu); - - if let Ok(user) = user_by_id { - let mut user: ActiveModel = user.into(); - - user.name = Set(form.name); - - user.update(&self.state.db).await.context(DBSnafu) - } else { - Err(UserError::NotFound { id }) - } - } - - /// Delete user by ID. - /// Before deleting the user, you must search for all the books they own in order to delete them beforehand, - /// then search for all the books they have borrowed in order to update the current holder to None. pub async fn delete(&self, user_id: i32) -> Result { - // get all - let owner_books = book::BookOperator::new(self.state.clone()) - .find_all_by_owner(user_id) - .await - .context(BookSnafu)?; - - // Delete all book with owner_id = current_user - for owner_book in owner_books { - book::BookOperator::new(self.state.clone()) - .delete(owner_book.id) - .await - .context(BookSnafu)?; - } - - let current_holder_books = book::BookOperator::new(self.state.clone()) - .find_all_by_current_holder(user_id) - .await - .context(BookSnafu)?; - - // Update all book with current Holder = current user - for current_holder_book in current_holder_books { - let form = BookForm { - title: current_holder_book.title, - authors: current_holder_book.authors, - owner_id: current_holder_book.owner_id, - description: current_holder_book.description, - comment: current_holder_book.comment, - current_holder_id: None, - }; - - book::BookOperator::new(self.state.clone()) - .update(current_holder_book.id, form) - .await - .context(BookSnafu)?; - } - let user: Option = Entity::find_by_id(user_id) .one(&self.state.db) .await diff --git a/src/routes/book.rs b/src/routes/book.rs index 8d4fa03..26545fb 100644 --- a/src/routes/book.rs +++ b/src/routes/book.rs @@ -4,17 +4,15 @@ use askama::Template; use askama_web::WebTemplate; use axum::{ Form, - body::Body, extract::{Path, Query, State}, - response::{IntoResponse, Redirect, Response}, + response::{IntoResponse, Redirect}, }; -use csv::Writer; use serde::Deserialize; use serde_with::{NoneAsEmptyString, serde_as}; use snafu::prelude::*; -use crate::{models::book::Model as BookModel, routes::router::Router, state::error::CSVSnafu}; -use crate::{models::user::Model as UserModel, state::error::IOSnafu}; +use crate::models::book::Model as BookModel; +use crate::models::user::Model as UserModel; use crate::{ models::{book::BookOperator, user::UserOperator}, @@ -55,7 +53,6 @@ struct BookIndexTemplate { current_page: u64, total_page: u64, base_query: String, - router: Router, } pub async fn index( @@ -69,13 +66,13 @@ pub async fn index( // Get all Users let users = UserOperator::new(state.clone()) - .all() + .list() .await .context(UserSnafu)?; // Get all Book filtered with query - let books_paginate = BookOperator::new(state.clone()) - .all_paginate(page, Some(query.clone())) + let books_paginate = BookOperator::new(state) + .list_paginate(page, Some(query.clone())) .await .context(BookSnafu)?; @@ -128,9 +125,6 @@ pub async fn index( current_page: books_paginate.current_page, total_page: books_paginate.total_page, base_query, - router: Router { - base_path: state.config.base_path, - }, }) } @@ -140,7 +134,6 @@ struct ShowBookTemplate { book: BookModel, owner: UserModel, current_holder: Option, - router: Router, } pub async fn show( @@ -173,9 +166,6 @@ pub async fn show( book, owner, current_holder, - router: Router { - base_path: state.config.base_path, - }, }) } @@ -208,23 +198,14 @@ pub async fn create( #[template(path = "books/new.html")] struct NewBookTemplate { users: Vec, - router: Router, } pub async fn new( State(state): State, ) -> Result { - let users = UserOperator::new(state.clone()) - .all() - .await - .context(UserSnafu)?; + let users = UserOperator::new(state).list().await.context(UserSnafu)?; - Ok(NewBookTemplate { - users, - router: Router { - base_path: state.config.base_path, - }, - }) + Ok(NewBookTemplate { users }) } #[derive(Template, WebTemplate)] @@ -232,7 +213,6 @@ pub async fn new( struct EditBookTemplate { users: Vec, book: BookModel, - router: Router, } pub async fn edit( @@ -240,21 +220,15 @@ pub async fn edit( Path(id): Path, ) -> Result { let users = UserOperator::new(state.clone()) - .all() + .list() .await .context(UserSnafu)?; - let book = BookOperator::new(state.clone()) + let book = BookOperator::new(state) .find_by_id(id) .await .context(BookSnafu)?; - Ok(EditBookTemplate { - users, - book, - router: Router { - base_path: state.config.base_path, - }, - }) + Ok(EditBookTemplate { users, book }) } pub async fn update( @@ -280,75 +254,3 @@ pub async fn delete( Ok(Redirect::to("/").into_response()) } - -/// Download CSV filter (no paginate) of all books -pub async fn download_csv( - State(state): State, - Query(query): Query, -) -> Result { - let books = BookOperator::new(state.clone()) - .all_filtered(Some(query)) - .await - .context(BookSnafu)?; - - let users = UserOperator::new(state).all().await.context(UserSnafu)?; - - let users_by_id: HashMap = users.into_iter().map(|u| (u.id, u)).collect(); - - let mut wtr = Writer::from_writer(vec![]); - wtr.write_record(&[ - "ID", - "Title", - "Author(s)", - "Description", - "Owner", - "Current Holder", - "Comment", - ]) - .context(CSVSnafu)?; - - for book in books { - let owner_format = match users_by_id.get(&book.owner_id).cloned().ok_or(UserSnafu) { - Ok(owner) => format!("{} (id: {})", owner.name.to_string(), owner.id), - Err(_) => "-".to_string(), - }; - - let current_holder = match users_by_id - // if current_holder_id is None, take 0. - // So get returns errors because user with id 0 can't exist - .get(&book.current_holder_id.unwrap_or(0)) - .cloned() - .ok_or(UserSnafu) - { - Ok(current_holder) => format!( - "{} (id: {})", - current_holder.name.to_string(), - current_holder.id - ), - Err(_) => "-".to_string(), - }; - - wtr.write_record(&[ - book.id.to_string(), - book.title, - book.authors, - book.description.unwrap_or_default(), - owner_format, - current_holder, - book.comment.unwrap_or_default(), - ]) - .context(CSVSnafu)?; - } - - wtr.flush().context(IOSnafu)?; - - let csv_bytes = wtr.into_inner(); - - match csv_bytes { - Ok(csv_bytes) => Ok(Response::builder() - .header("Content-Type", "text/csv") - .body(Body::from(csv_bytes)) - .unwrap()), - Err(_) => Ok(Redirect::to("/").into_response()), - } -} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 2bbba56..011ff79 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,3 +1,2 @@ pub mod book; -pub mod router; pub mod user; diff --git a/src/routes/router.rs b/src/routes/router.rs deleted file mode 100644 index 52bcd0b..0000000 --- a/src/routes/router.rs +++ /dev/null @@ -1,54 +0,0 @@ -#[derive(Clone)] -pub struct Router { - pub base_path: String, -} - -impl Router { - pub fn assets(&self, path: &str) -> String { - if self.base_path.is_empty() || self.base_path == "/" { - format!("/{}", path) - } else { - format!("{}/{}", self.base_path.trim_end_matches('/'), path) - } - } - - pub fn root_path(&self) -> String { - format!("{}/", &self.base_path) - } - - // BOOKS ROUTES - - pub fn new_book_path(&self) -> String { - format!("{}/books/new", &self.base_path) - } - - pub fn create_book_path(&self) -> String { - format!("{}/books", &self.base_path) - } - - pub fn update_book_path(&self, id: &i32) -> String { - format!("{}/books/{}", &self.base_path, id) - } - - pub fn download_csv_book_path(&self) -> String { - format!("{}/books/download_csv", &self.base_path) - } - - // USERS - - pub fn index_user_path(&self) -> String { - format!("{}/users", &self.base_path) - } - - pub fn new_user_path(&self) -> String { - format!("{}/users/new", &self.base_path) - } - - pub fn create_user_path(&self) -> String { - format!("{}/users", &self.base_path) - } - - pub fn update_user_path(&self, id: &i32) -> String { - format!("{}/users/{}", &self.base_path, id) - } -} diff --git a/src/routes/user.rs b/src/routes/user.rs index 04eed56..8a49cb4 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -4,11 +4,10 @@ use askama::Template; use askama_web::WebTemplate; use axum::{ Form, - extract::{Path, Query, State}, + extract::{Path, State}, response::Redirect, }; use serde::Deserialize; -use serde_with::{NoneAsEmptyString, serde_as}; use snafu::prelude::*; use crate::{ @@ -16,7 +15,6 @@ use crate::{ book::BookOperator, user::{self, UserOperator}, }, - routes::router::Router, state::{ AppState, error::{AppStateError, BookSnafu, UserSnafu}, @@ -26,43 +24,23 @@ use crate::{ #[derive(Template, WebTemplate)] #[template(path = "users/index.html")] struct UsersIndexTemplate { - users_with_books_number: Vec, - query: IndexQuery, - router: Router, -} - -pub struct UserWithBookNumber { - /// the user model - pub user: user::Model, - /// the number of books owned by this user - pub owner_book_number: usize, - /// the number of books borrowed by this user - pub borrowed_book_number: usize, -} - -#[serde_as] -#[derive(Deserialize, Clone)] -pub struct IndexQuery { - #[serde(default)] - #[serde_as(as = "NoneAsEmptyString")] - pub name: Option, + user_with_books_number: Vec<(user::Model, usize, usize)>, } pub async fn index( State(state): State, - Query(query): Query, ) -> Result { let users = UserOperator::new(state.clone()) - .all_filtered(query.clone()) + .list() .await .context(UserSnafu)?; let books = BookOperator::new(state.clone()) - .all() + .list() .await .context(BookSnafu)?; - let mut result: Vec = Vec::with_capacity(users.len()); + let mut result: Vec<(user::Model, usize, usize)> = vec![]; let mut owner_books: HashMap = HashMap::new(); let mut borrowed_books: HashMap = HashMap::new(); @@ -78,19 +56,11 @@ pub async fn index( let owner_books_size = owner_books.get(&user.id).unwrap_or(&0); let borrowed_books_size = borrowed_books.get(&user.id).unwrap_or(&0); - result.push(UserWithBookNumber { - user, - owner_book_number: *owner_books_size, - borrowed_book_number: *borrowed_books_size, - }); + result.push((user, *owner_books_size, *borrowed_books_size)); } Ok(UsersIndexTemplate { - users_with_books_number: result, - query, - router: Router { - base_path: state.config.base_path, - }, + user_with_books_number: result, }) } @@ -103,7 +73,7 @@ pub async fn create( State(state): State, Form(form): Form, ) -> Result { - let _ = UserOperator::new(state) + let _user = UserOperator::new(state) .create(form) .await .context(UserSnafu)?; @@ -111,19 +81,6 @@ pub async fn create( Ok(Redirect::to("/users")) } -pub async fn update( - State(state): State, - Path(id): Path, - Form(form): Form, -) -> Result { - let _ = UserOperator::new(state) - .update(id, form) - .await - .context(UserSnafu)?; - - Ok(Redirect::to("/users")) -} - pub async fn delete( State(state): State, Path(id): Path, @@ -135,41 +92,3 @@ pub async fn delete( Ok(Redirect::to("/users")) } - -#[derive(Template, WebTemplate)] -#[template(path = "users/edit.html")] -struct EditTemplate { - user: user::Model, - router: Router, -} - -pub async fn edit( - State(state): State, - Path(id): Path, -) -> Result { - let user = UserOperator::new(state.clone()) - .find_by_id(id) - .await - .context(UserSnafu)?; - - Ok(EditTemplate { - user, - router: Router { - base_path: state.config.base_path, - }, - }) -} - -#[derive(Template, WebTemplate)] -#[template(path = "users/new.html")] -struct NewTemplate { - router: Router, -} - -pub async fn new(State(state): State) -> impl axum::response::IntoResponse { - NewTemplate { - router: Router { - base_path: state.config.base_path, - }, - } -} diff --git a/src/state/config.rs b/src/state/config.rs index f137f8a..4f81560 100644 --- a/src/state/config.rs +++ b/src/state/config.rs @@ -32,8 +32,6 @@ pub enum ConfigError { pub struct AppConfig { #[serde(default = "AppConfig::default_sqlite_path")] pub database_path: Utf8PathBuf, - pub locale: String, - pub base_path: String, pub listener: Listener, } @@ -41,8 +39,6 @@ impl Default for AppConfig { fn default() -> Self { AppConfig { database_path: Self::default_sqlite_path(), - base_path: Self::default_base_path(), - locale: Self::default_locale(), listener: Listener::default(), } } @@ -96,14 +92,6 @@ impl AppConfig { Self::config_path().join("BookForge.toml") } - fn default_locale() -> String { - "en".to_string() - } - - fn default_base_path() -> String { - "".to_string() - } - pub fn default_sqlite_path() -> Utf8PathBuf { Self::config_path().join("db.sqlite") } diff --git a/src/state/error.rs b/src/state/error.rs index 6a031b6..36dedc1 100644 --- a/src/state/error.rs +++ b/src/state/error.rs @@ -1,15 +1,17 @@ use askama::Template; use askama_web::WebTemplate; use axum::response::{IntoResponse, Response}; -use log::error; use snafu::prelude::*; use crate::{ models::{book::BookError, user::UserError}, - routes::router::Router, state::config::ConfigError, }; +#[derive(Template, WebTemplate)] +#[template(path = "error.html")] +struct ErrorTemplate {} + #[derive(Snafu, Debug)] #[snafu(visibility(pub))] pub enum AppStateError { @@ -34,44 +36,10 @@ pub enum AppStateError { Book { source: BookError, }, - #[snafu(display("CSV Error"))] - CSV { - source: csv::Error, - }, - #[snafu(display("IO Error"))] - IO { - source: std::io::Error, - }, -} - -#[derive(Template, WebTemplate)] -#[template(path = "error.html")] -struct ErrorTemplate { - state: AppStateErrorContext, - router: Router, -} - -struct AppStateErrorContext { - pub errors: Vec, -} - -impl From for AppStateErrorContext { - fn from(e: AppStateError) -> Self { - error!("{:?}", e); - - Self { errors: vec![e] } - } } impl IntoResponse for AppStateError { fn into_response(self) -> Response { - let error_context = AppStateErrorContext::from(self); - ErrorTemplate { - state: error_context, - router: Router { - base_path: "".to_string(), - }, - } - .into_response() + ErrorTemplate {}.into_response() } } diff --git a/templates/404.html b/templates/404.html deleted file mode 100644 index 6f35ef6..0000000 --- a/templates/404.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} - -{% block title %} - {{ t!("error.error_404.title_tag") }} -{% endblock %} - -{% block main %} -
-

{{ t!("error.error_404.title") }}

-

{{ t!("error.error_404.subtitle") }}

- {{ t!("error.error_404.button") }} -
-{% endblock %} diff --git a/templates/base.html b/templates/base.html index bc0ed7e..5e2038d 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,14 +2,13 @@ - {% block title %}{{ t!("name") }}{% endblock %} + {% block title %}Book Forge{% endblock %} - - - + + - - + + {% block extra_head %}{% endblock extra_head %} @@ -26,7 +25,8 @@ {% endblock %} - - + + + diff --git a/templates/books/edit.html b/templates/books/edit.html index f80be6a..6964b99 100644 --- a/templates/books/edit.html +++ b/templates/books/edit.html @@ -2,27 +2,23 @@ {% import "components/typography.html" as typography %} {% import "components/cards.html" as cards %} -{% block title %} - {{ t!("book.edit.title_tag") }} -{% endblock %} - {% block main %} - {{ typography::heading(t!("book.edit.title")) }} + {{ typography::heading("Editer") }} {% call cards::card() %} -
+
- +
- +
- + {% match book.current_holder_id %} @@ -56,7 +52,7 @@
- + {% match book.description %} {% when Some with (description) %} @@ -66,7 +62,7 @@
- + {% match book.comment %} {% when Some with (comment) %} @@ -76,7 +72,7 @@
- +
{% endcall %} diff --git a/templates/books/new.html b/templates/books/new.html index 30deb91..b37a020 100644 --- a/templates/books/new.html +++ b/templates/books/new.html @@ -1,34 +1,53 @@ {% extends "base.html" %} {% import "components/typography.html" as typography %} {% import "components/cards.html" as cards %} -{% import "components/inputs.html" as form_helpers %} - -{% block title %} - {{ t!("book.new.title_tag") }} -{% endblock %} {% block main %} - {{ typography::heading(t!("book.new.title")) }} + {{ typography::heading("New book") }} {% call cards::card() %} -
- {{ form_helpers::input("title", t!("book.attributes.title"), is_required = true, placeholder = "Ex: La Petite Dernière") }} - {{ form_helpers::input("authors", t!("book.attributes.authors"), is_required = true, placeholder = "Ex: Fatima Daas") }} + +
+ + +
- {% call(option) form_helpers::select("owner_id", t!("book.attributes.owner"), users, is_required = true) %} - - {% endcall %} +
+ + +
- {% call(option) form_helpers::select("current_holder_id", t!("book.attributes.current_holder"), users, is_required = false) %} - - {% endcall %} +
+ + +
- {{ form_helpers::textarea("description", t!("book.attributes.description"), rows = 5, is_required = false, placeholder = "Ex: Je m’appelle Fatima Daas. Je suis la mazoziya, la petite dernière. Celle à laquelle on ne s’est pas préparé. Française d’origine algérienne.") }} +
+ + +
- {{ form_helpers::textarea("comment", t!("book.attributes.comment"), rows = 3, is_required = false, placeholder = "Ex: I recommend it, it's great!") }} +
+ + +
+ +
+ + +
- +
{% endcall %} diff --git a/templates/books/show.html b/templates/books/show.html index 61042f2..aec5bda 100644 --- a/templates/books/show.html +++ b/templates/books/show.html @@ -4,43 +4,39 @@ {% import "components/fields.html" as fields %} {% import "components/cards.html" as cards %} -{% block title %} - {{ t!("book.show.title_tag") }} -{% endblock %} - {% block main %} {{ typography::book_heading(book.title, book, show = false) }} {% call cards::card() %} -
-
{{ t!("book.show.book_details") }}
- {{ fields::field(t!("book.attributes.title"), book.title) }} - {{ fields::field(t!("book.attributes.authors"), book.authors) }} +
+
Book details
+ {{ fields::field("Name", book.title) }} + {{ fields::field("Authors", book.authors) }} {% match book.description %} {% when Some with (description) %} - {{ fields::field(t!("book.attributes.description"), description) }} + {{ fields::field("Description", description) }} {% when None %} - {{ fields::field(t!("book.attributes.description"), "-") }} + {{ fields::field("Description", "-") }} {% endmatch %} -
{{ t!("book.show.user_details") }}
- {{ fields::field(t!("book.attributes.owner"), owner.name) }} +
User Details
+ {{ fields::field("Owner", owner.name) }} {% match current_holder %} {% when Some with (current_holder) %} - {{ fields::field(t!("book.attributes.current_holder"), current_holder.name) }} + {{ fields::field("Current Holder", current_holder.name) }} {% when None %} - {{ fields::field(t!("book.attributes.current_holder"), "-") }} + {{ fields::field("Current Holder", "-") }} {% endmatch %} -
{{ t!("book.show.more_informations") }}
+
More Informations
{% match book.comment %} {% when Some with (comment) %} - {{ fields::field(t!("book.attributes.comment"), comment) }} + {{ fields::field("Comment", comment) }} {% when None %} - {{ fields::field(t!("book.attributes.comment"), "-") }} + {{ fields::field("Comment", "-") }} {% endmatch %}
{% endcall %} diff --git a/templates/components/dropdown.html b/templates/components/dropdown.html index 7b0e55d..a792d72 100644 --- a/templates/components/dropdown.html +++ b/templates/components/dropdown.html @@ -11,40 +11,21 @@
{% endmacro %} -{% macro crud_dropdown_button(book, label, sub_path, show = true) %} +{% macro book_dropdown_button(book, show = true) %} - - - {% endmacro %} diff --git a/templates/components/inputs.html b/templates/components/inputs.html deleted file mode 100644 index 6b6082d..0000000 --- a/templates/components/inputs.html +++ /dev/null @@ -1,43 +0,0 @@ -{% macro input(name, label, value = "", type = "text", is_required = false, placeholder = "", margin_bottom = true) %} -
- - -
-{% endmacro %} - -{% macro select(name, label, options, selected_value = "", is_required = false, margin_bottom = true) -%} -
- - -
-{%- endmacro %} - -{% macro textarea(name, label, value = "", rows = 2, is_required = false, placeholder = "", margin_bottom = true) %} -
- - -
-{% endmacro %} - diff --git a/templates/components/typography.html b/templates/components/typography.html index 3598c9a..1068b83 100644 --- a/templates/components/typography.html +++ b/templates/components/typography.html @@ -21,7 +21,7 @@
- {{ dropdown::crud_dropdown_button(book, t!("common.actions"), "books", show) }} + {{ dropdown::book_dropdown_button(book, show) }}
{% endmacro %} diff --git a/templates/error.html b/templates/error.html index 09e125b..59fd4d6 100644 --- a/templates/error.html +++ b/templates/error.html @@ -1,17 +1 @@ -{% extends "base.html" %} - -{% block title %} - {{ t!("error.generic.title_tag") }} -{% endblock %} - -{% block main %} -
-

{{ t!("error.generic.title") }}

-
- {% for error in state.errors %} -

{{ error }}

- {% endfor %} -
- {{ t!("error.error_404.button") }} -
-{% endblock %} +Error diff --git a/templates/index.html b/templates/index.html index 2701d7b..a1882c9 100644 --- a/templates/index.html +++ b/templates/index.html @@ -3,22 +3,14 @@ {% import "components/dropdown.html" as dropdown %} {% import "components/cards.html" as cards %} -{% block title %} - {{ t!("book.index.title_tag") }} -{% endblock %} - {% block main %} - {% call typography::heading(t!("book.index.title")) %} - - {{ t!("common.download") }} (csv) - - {% endcall %} + {{ typography::heading("All books") }} {% call cards::card() %}
- + {% match query.title %} {% when Some with (value) %} @@ -28,7 +20,7 @@
- + {% match query.authors %} {% when Some with (value) %} @@ -39,9 +31,9 @@
- + - {% match query.owner_id %} {% when Some with (owner_id) %} @@ -61,9 +53,9 @@
- + - {% match query.current_holder_id %} {% when Some with (current_holder_id) %} @@ -83,84 +75,67 @@
- -
- -
{% endcall %} {% call cards::card() %} - {% if books_with_user.is_empty() %} -
-

{{ t!("common.no_result") }}

- - - {{ t!("book.new.button_short") }} - -
- {% else %} - - - - - - - - - - - - - {% for book_user in books_with_user %} - - - - - - - - - {% endfor %} - -
#{{ t!("book.attributes.title") }}{{ t!("book.attributes.authors") }}{{ t!("book.attributes.owner") }}{{ t!("book.attributes.current_holder") }}{{ t!("common.actions") }}
{{ book_user.book.id }}{{ book_user.book.title }}{{ book_user.book.authors }}{{ book_user.owner.name }} - {% match book_user.current_holder %} - {% when Some with (current_holder) %} - {{ current_holder.name }} - {% when None %} - - - {% endmatch %} - - {{ dropdown::crud_dropdown_button(book_user.book, t!("common.actions"), "books") }} -
- - {% if total_page > 1 %} -
- -
- {% endif %} + + + + + + + + + + + + + {% for book_user in books_with_user %} + + + + + + + + + {% endfor %} + +
#NameAuthor(s)OwnerCurrent HolderActions
{{ book_user.book.id }}{{ book_user.book.title }}{{ book_user.book.authors }}{{ book_user.owner.name }} + {% match book_user.current_holder %} + {% when Some with (current_holder) %} + {{ current_holder.name }} + {% when None %} + - + {% endmatch %} + + {{ dropdown::book_dropdown_button(book_user.book) }} +
+ {% if total_page > 1 %} + {% endif %} {% endcall %} {% endblock %} diff --git a/templates/layout/footer.html b/templates/layout/footer.html index 3f29c8b..3ddc19e 100644 --- a/templates/layout/footer.html +++ b/templates/layout/footer.html @@ -1,5 +1,5 @@
-

{{ t!("footer.message") }}

+

Made with Love & Fuck a Fascist !

-
+ \ No newline at end of file diff --git a/templates/layout/header.html b/templates/layout/header.html index 114aa1f..3f64943 100644 --- a/templates/layout/header.html +++ b/templates/layout/header.html @@ -1,33 +1,34 @@ + \ No newline at end of file diff --git a/templates/users/edit.html b/templates/users/edit.html deleted file mode 100644 index 017ef04..0000000 --- a/templates/users/edit.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base.html" %} -{% import "components/typography.html" as typography %} -{% import "components/cards.html" as cards %} -{% import "components/inputs.html" as form_helpers %} - -{% block title %} - {{ t!("book.edit.title_tag") }} -{% endblock %} - -{% block main %} - {{ typography::heading(t!("user.edit.title")) }} - - {% call cards::card() %} -
-
-
- {{ form_helpers::input("name", t!("user.attributes.name"), value = user.name, is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }} -
- -
- -
-
-
- {% endcall %} -{% endblock %} diff --git a/templates/users/index.html b/templates/users/index.html index 835aa99..6d424d2 100644 --- a/templates/users/index.html +++ b/templates/users/index.html @@ -1,76 +1,46 @@ {% extends "base.html" %} {% import "components/typography.html" as typography %} -{% import "components/dropdown.html" as dropdown %} {% import "components/cards.html" as cards %} -{% import "components/inputs.html" as form_helpers %} - -{% block title %} - {{ t!("user.index.title_tag") }} -{% endblock %} {% block main %} - {% call typography::heading(t!("user.index.title")) %} - {{ t!("user.index.button") }} + {{ typography::heading("All users") }} + + {% call cards::card() %} + + + + + + + + + + + + {% for (user, book_size, borrowed_book) in user_with_books_number %} + + + + + + + + {% endfor %} + +
#NameOwner bookBorrowed bookActions
{{ user.id }}{{ user.name }}{{ book_size }}{{ borrowed_book }} +
+ +
+
{% endcall %} {% call cards::card() %} -
-
-
- - {% match query.name %} - {% when Some with (value) %} - - {% when None %} - - {% endmatch %} -
+ + + -
- -
- - -
+
{% endcall %} - {% call cards::card() %} - {% if users_with_books_number.is_empty() %} -
-

{{ t!("common.no_result") }}

- - - {{ t!("user.index.button") }} - -
- {% else %} - - - - - - - - - - - - {% for user_information in users_with_books_number %} - - - - - - - - {% endfor %} - -
#{{ t!("user.attributes.name") }}{{ t!("user.attributes.owner_books") }}{{ t!("user.attributes.borrowed_books") }}{{ t!("common.actions") }}
{{ user_information.user.id }}{{ user_information.user.name }}{{ user_information.owner_book_number }}{{ user_information.borrowed_book_number }} - {{ dropdown::crud_dropdown_button(user_information.user, t!("common.actions"), "users", show = false) }} -
- {% endif %} - {% endcall %} {% endblock %} diff --git a/templates/users/new.html b/templates/users/new.html deleted file mode 100644 index 6213b3a..0000000 --- a/templates/users/new.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.html" %} -{% import "components/typography.html" as typography %} -{% import "components/cards.html" as cards %} -{% import "components/inputs.html" as form_helpers %} - -{% block title %} - {{ t!("user.new.title_tag") }} -{% endblock %} - -{% block main %} - {{ typography::heading(t!("user.new.title")) }} - - {% call cards::card() %} -
-
-
- {{ form_helpers::input("name", t!("user.attributes.name"), is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }} -
-
- -
-
-
- {% endcall %} -{% endblock %}