Implemented mail notifications.
This commit is contained in:
Generated
+404
-54
@@ -331,6 +331,54 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.6.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "3.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.71"
|
version = "1.0.71"
|
||||||
@@ -668,7 +716,17 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chumsky"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23170228b96236b5a7299057ac284a321457700bc8c41a4476052f0f4ba5349d"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"stacker",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -723,6 +781,12 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
|
checksum = "186dce98367766de751c42c4f03970fc60fc012296e706ccbb9d5df9b6c1e271"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "config"
|
name = "config"
|
||||||
version = "0.13.3"
|
version = "0.13.3"
|
||||||
@@ -817,6 +881,16 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -1077,6 +1151,22 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "email-encoding"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.2",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "email_address"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.32"
|
version = "0.8.32"
|
||||||
@@ -1087,16 +1177,26 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_filter"
|
||||||
version = "0.10.1"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"humantime",
|
|
||||||
"is-terminal",
|
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
"regex",
|
||||||
"termcolor",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "env_logger"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"env_filter",
|
||||||
|
"humantime",
|
||||||
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1113,7 +1213,7 @@ checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"errno-dragonfly",
|
"errno-dragonfly",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1134,7 +1234,7 @@ checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"home",
|
"home",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1177,6 +1277,21 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -1493,12 +1608,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.4.3"
|
version = "0.4.3"
|
||||||
@@ -1539,7 +1648,18 @@ version = "0.5.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hostname"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"match_cfg",
|
||||||
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1636,6 +1756,16 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "idna"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "if_chain"
|
name = "if_chain"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -1692,17 +1822,6 @@ version = "0.3.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b"
|
checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi 0.3.3",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.10.5"
|
||||||
@@ -2012,6 +2131,35 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lettre"
|
||||||
|
version = "0.11.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a48c2e9831b370bc2d7233c2620298c45f3a158ed6b4b8d7416b2ada5a268fd8"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"base64 0.21.2",
|
||||||
|
"chumsky",
|
||||||
|
"email-encoding",
|
||||||
|
"email_address",
|
||||||
|
"fastrand",
|
||||||
|
"futures-io",
|
||||||
|
"futures-util",
|
||||||
|
"hostname",
|
||||||
|
"httpdate",
|
||||||
|
"idna 0.5.0",
|
||||||
|
"mime",
|
||||||
|
"native-tls",
|
||||||
|
"nom",
|
||||||
|
"once_cell",
|
||||||
|
"quoted_printable",
|
||||||
|
"socket2 0.5.4",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
"url",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.147"
|
version = "0.2.147"
|
||||||
@@ -2117,6 +2265,12 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match_cfg"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
@@ -2183,7 +2337,25 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "native-tls"
|
||||||
|
version = "0.2.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"openssl",
|
||||||
|
"openssl-probe",
|
||||||
|
"openssl-sys",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2261,7 +2433,7 @@ version = "1.15.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.2.6",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2277,6 +2449,50 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl"
|
||||||
|
version = "0.10.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.4.0",
|
||||||
|
"cfg-if",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"openssl-macros",
|
||||||
|
"openssl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.48",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-sys"
|
||||||
|
version = "0.9.99"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
"vcpkg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pad-adapter"
|
name = "pad-adapter"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -2303,7 +2519,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2486,6 +2702,15 @@ dependencies = [
|
|||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psm"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ptr_meta"
|
name = "ptr_meta"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@@ -2542,6 +2767,12 @@ dependencies = [
|
|||||||
"syn 2.0.48",
|
"syn 2.0.48",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quoted_printable"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "79ec282e887b434b68c18fe5c121d38e72a5cf35119b59e54ec5b992ea9c8eb0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "radium"
|
name = "radium"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@@ -2644,6 +2875,7 @@ dependencies = [
|
|||||||
"leptos_actix",
|
"leptos_actix",
|
||||||
"leptos_meta",
|
"leptos_meta",
|
||||||
"leptos_router",
|
"leptos_router",
|
||||||
|
"lettre",
|
||||||
"log",
|
"log",
|
||||||
"pwhash",
|
"pwhash",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -2778,7 +3010,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2836,6 +3068,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -2858,6 +3099,29 @@ version = "4.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "self_cell"
|
name = "self_cell"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -3132,7 +3396,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3381,6 +3645,19 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stacker"
|
||||||
|
version = "0.1.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"psm",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stringprep"
|
name = "stringprep"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -3453,16 +3730,7 @@ dependencies = [
|
|||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3541,7 +3809,17 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2 0.4.9",
|
"socket2 0.4.9",
|
||||||
"windows-sys",
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3748,7 +4026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
|
checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna 0.4.0",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3758,6 +4036,12 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
@@ -3774,7 +4058,7 @@ version = "0.16.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd"
|
checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna",
|
"idna 0.4.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3979,7 +4263,7 @@ version = "0.48.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3988,7 +4272,16 @@ version = "0.48.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3997,13 +4290,28 @@ version = "0.48.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm 0.48.0",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.48.0",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.48.0",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.48.0",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.48.0",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm 0.48.0",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm 0.52.0",
|
||||||
|
"windows_aarch64_msvc 0.52.0",
|
||||||
|
"windows_i686_gnu 0.52.0",
|
||||||
|
"windows_i686_msvc 0.52.0",
|
||||||
|
"windows_x86_64_gnu 0.52.0",
|
||||||
|
"windows_x86_64_gnullvm 0.52.0",
|
||||||
|
"windows_x86_64_msvc 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4012,42 +4320,84 @@ version = "0.48.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.19"
|
version = "0.5.19"
|
||||||
|
|||||||
+3
-1
@@ -30,9 +30,10 @@ futures-util = "0.3.28"
|
|||||||
regex = "1.10.2"
|
regex = "1.10.2"
|
||||||
toml = "0.8.8"
|
toml = "0.8.8"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
env_logger = "0.10.1"
|
env_logger = "0.11"
|
||||||
getopts = "0.2.21"
|
getopts = "0.2.21"
|
||||||
leptos-use = "0.10.1"
|
leptos-use = "0.10.1"
|
||||||
|
lettre = {version = "0.11", features = ["tokio1-native-tls", "smtp-transport", "file-transport"], optional = true}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||||
@@ -43,6 +44,7 @@ ssr = [
|
|||||||
"dep:leptos_actix",
|
"dep:leptos_actix",
|
||||||
"dep:actix-session",
|
"dep:actix-session",
|
||||||
"dep:sqlx",
|
"dep:sqlx",
|
||||||
|
"dep:lettre",
|
||||||
"leptos/ssr",
|
"leptos/ssr",
|
||||||
"leptos_meta/ssr",
|
"leptos_meta/ssr",
|
||||||
"leptos_router/ssr",
|
"leptos_router/ssr",
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
use crate::backend::get_pool;
|
use crate::backend::get_pool;
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use crate::config::Mailing;
|
||||||
|
use crate::config::MailTransport;
|
||||||
|
use crate::backend::data::ResSumWithItems;
|
||||||
|
use lettre::message::Message as LettreMessage;
|
||||||
|
use lettre::{AsyncSmtpTransport, AsyncFileTransport, AsyncTransport, Tokio1Executor};
|
||||||
|
use lettre::transport::smtp::authentication::Credentials;
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
pub async fn message_for_type(msg_type: &MessageType, pool: &PgPool) -> Result<Message, Error> {
|
pub async fn message_for_type(msg_type: &MessageType, pool: &PgPool) -> Result<Message, Error> {
|
||||||
Ok(query_as::<_, Message>("SELECT * FROM message WHERE msg_type = $1")
|
Ok(query_as::<_, Message>("SELECT * FROM message WHERE msg_type = $1")
|
||||||
@@ -48,6 +55,73 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MailMessage {
|
||||||
|
reply_to: String,
|
||||||
|
to: String,
|
||||||
|
subject: String,
|
||||||
|
text: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MailMessage {
|
||||||
|
pub fn new(reply_to: String, to: String, message: Message, reservation: &ResSumWithItems) -> Self {
|
||||||
|
Self {
|
||||||
|
reply_to,
|
||||||
|
to,
|
||||||
|
subject: message.subject,
|
||||||
|
text: Self::replace_body_vars(message.text, &reservation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace_body_vars(text: String, reservation: &ResSumWithItems) -> String {
|
||||||
|
text
|
||||||
|
.replace("#date#", &reservation.summary.date.format("%d. %m. %Y").to_string())
|
||||||
|
.replace("#summary#", &{
|
||||||
|
let mut sum = "".to_string();
|
||||||
|
for p in &reservation.reservations {
|
||||||
|
sum = sum.add(&format!("{}: {} - {}",
|
||||||
|
p.property.name,
|
||||||
|
p.reservation.from.format("%H:%M").to_string(), p.reservation.to.format("%H:%M").to_string()));
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_mail(&self, from: String) -> Result<LettreMessage, AppError> {
|
||||||
|
Ok(LettreMessage::builder()
|
||||||
|
.from(from.parse()?)
|
||||||
|
.reply_to(self.reply_to.parse()?)
|
||||||
|
.to(self.to.parse()?)
|
||||||
|
.subject(&self.subject)
|
||||||
|
.body(self.text.clone())?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mailing {
|
||||||
|
pub async fn send_mail(&self, msg: MailMessage) -> Result<(), AppError> {
|
||||||
|
match self.transport() {
|
||||||
|
MailTransport::Smtp => {
|
||||||
|
let transport = if self.tls().unwrap_or(false) {
|
||||||
|
AsyncSmtpTransport::<Tokio1Executor>::starttls_relay(&self.server().clone().unwrap_or_default())
|
||||||
|
} else {
|
||||||
|
AsyncSmtpTransport::<Tokio1Executor>::relay(&self.server().clone().unwrap_or_default())
|
||||||
|
}.expect("Cannot create SMTP mail transport");
|
||||||
|
if self.user().is_some() && self.password().is_some() {
|
||||||
|
let cred = Credentials::new(self.user().clone().unwrap(), self.password().clone().unwrap());
|
||||||
|
transport.credentials(cred).build().send(msg.build_mail(self.from().to_string())?).await?;
|
||||||
|
} else {
|
||||||
|
transport.build().send(msg.build_mail(self.from().to_string())?).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MailTransport::File => {
|
||||||
|
AsyncFileTransport::<Tokio1Executor>::new(self.path().clone().unwrap_or_default())
|
||||||
|
.send(msg.build_mail(self.from().to_string())?).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
|
|||||||
+15
-3
@@ -54,27 +54,39 @@ cfg_if!{
|
|||||||
use actix_web::web::Data;
|
use actix_web::web::Data;
|
||||||
use leptos_actix::extract;
|
use leptos_actix::extract;
|
||||||
use leptos::ServerFnError;
|
use leptos::ServerFnError;
|
||||||
|
use crate::config::Mailing;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AppData {
|
pub struct AppData {
|
||||||
db_pool: PgPool
|
db_pool: PgPool,
|
||||||
|
mailer: Mailing
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppData {
|
impl AppData {
|
||||||
pub fn new(db_pool: PgPool) -> Self {
|
pub fn new(db_pool: PgPool, mailer: Mailing) -> Self {
|
||||||
Self {
|
Self {
|
||||||
db_pool
|
db_pool,
|
||||||
|
mailer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn db_pool(&self) -> &PgPool {
|
pub fn db_pool(&self) -> &PgPool {
|
||||||
&self.db_pool
|
&self.db_pool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mailer(&self) -> &Mailing {
|
||||||
|
&self.mailer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_pool() -> Result<PgPool, ServerFnError> {
|
pub async fn get_pool() -> Result<PgPool, ServerFnError> {
|
||||||
let data = extract::<Data<AppData>>().await?;
|
let data = extract::<Data<AppData>>().await?;
|
||||||
Ok(data.db_pool().clone())
|
Ok(data.db_pool().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_mailing() -> Result<Mailing, ServerFnError> {
|
||||||
|
let data = extract::<Data<AppData>>().await?;
|
||||||
|
Ok(data.mailer().clone())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+106
-15
@@ -13,8 +13,16 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use futures_util::future::join_all;
|
use futures_util::future::join_all;
|
||||||
use crate::backend::data::{ReservationSum, ReservationState, ResWithProperty, Customer};
|
use log::warn;
|
||||||
|
use crate::backend::data::{ReservationSum, ReservationState, ResWithProperty, Customer, Message, MessageType};
|
||||||
use crate::backend::get_pool;
|
use crate::backend::get_pool;
|
||||||
|
use crate::backend::get_mailing;
|
||||||
|
use crate::backend::mail::MailMessage;
|
||||||
|
use crate::backend::mail::get_message;
|
||||||
|
use crate::error::AppError;
|
||||||
|
use sqlx::PgPool;
|
||||||
|
use crate::backend::user::admin_email;
|
||||||
|
use crate::backend::user::emails_for_notify;
|
||||||
|
|
||||||
async fn find_sum_by_uuid(uuid: &Uuid, tx: &mut Transaction<'_, Postgres>) -> Result<ReservationSum, Error> {
|
async fn find_sum_by_uuid(uuid: &Uuid, tx: &mut Transaction<'_, Postgres>) -> Result<ReservationSum, Error> {
|
||||||
let reservation = query_as::<_, ReservationSum>("SELECT * FROM reservation_sum WHERE uuid = $1")
|
let reservation = query_as::<_, ReservationSum>("SELECT * FROM reservation_sum WHERE uuid = $1")
|
||||||
@@ -43,6 +51,39 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn reservation_by_uuid(uuid: Uuid) -> Result<ResSumWithItems, ServerFnError> {
|
||||||
|
let pool = get_pool().await?;
|
||||||
|
let summary = query_as::<_, ReservationSum>("SELECT * FROM reservation_sum WHERE uuid = $1")
|
||||||
|
.bind(uuid)
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await?;
|
||||||
|
let sum_id = summary.id();
|
||||||
|
let cust_id = summary.customer;
|
||||||
|
|
||||||
|
Ok(ResSumWithItems{
|
||||||
|
summary,
|
||||||
|
customer: customer_for_reservation(cust_id, &pool).await?,
|
||||||
|
reservations: items_for_reservation(sum_id, &pool).await?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn items_for_reservation(id: i32, pool: &PgPool) -> Result<Vec<ResWithProperty>, ServerFnError> {
|
||||||
|
Ok(query_as::<_, ResWithProperty>(
|
||||||
|
"SELECT r.id, r.from, r.to, r.property, r.summary, p.name, p,description \
|
||||||
|
FROM reservation as r \
|
||||||
|
JOIN property as p ON r.property = p.id WHERE r.summary = $1")
|
||||||
|
.bind(id)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn customer_for_reservation(id: i32, pool: &PgPool) -> Result<Customer, ServerFnError> {
|
||||||
|
Ok(query_as::<_, Customer>("SELECT * FROM customer WHERE id = $1")
|
||||||
|
.bind(id)
|
||||||
|
.fetch_one(pool)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
|
||||||
async fn reservations_in_range(from: &NaiveDate, to: &NaiveDate, state: Option<ReservationState>) -> Result<Vec<ResSumWithItems>, ServerFnError> {
|
async fn reservations_in_range(from: &NaiveDate, to: &NaiveDate, state: Option<ReservationState>) -> Result<Vec<ResSumWithItems>, ServerFnError> {
|
||||||
let pool = get_pool().await?;
|
let pool = get_pool().await?;
|
||||||
let sums = if let Some(s) = state {
|
let sums = if let Some(s) = state {
|
||||||
@@ -74,18 +115,9 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
return Ok(vec![])
|
return Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
let res: Result<Vec<ResSumWithItems>, Error> = join_all(sums.into_iter().map(|s| async {
|
let res: Result<Vec<ResSumWithItems>, ServerFnError> = join_all(sums.into_iter().map(|s| async {
|
||||||
let reservations = query_as::<_, ResWithProperty>(
|
let reservations = items_for_reservation(s.id(), &pool).await?;
|
||||||
"SELECT r.id, r.from, r.to, r.property, r.summary, p.name, p,description \
|
let customer = customer_for_reservation(s.customer, &pool).await?;
|
||||||
FROM reservation as r \
|
|
||||||
JOIN property as p ON r.property = p.id WHERE r.summary = $1")
|
|
||||||
.bind(s.id())
|
|
||||||
.fetch_all(&pool)
|
|
||||||
.await?;
|
|
||||||
let customer = query_as::<_, Customer>("SELECT * FROM customer WHERE id = $1")
|
|
||||||
.bind(s.customer)
|
|
||||||
.fetch_one(&pool)
|
|
||||||
.await?;
|
|
||||||
Ok(ResSumWithItems {
|
Ok(ResSumWithItems {
|
||||||
summary: s,
|
summary: s,
|
||||||
customer,
|
customer,
|
||||||
@@ -106,6 +138,51 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn notify_new_all(admin_mail: String, reservation: &ResSumWithItems) -> Result<(), AppError> {
|
||||||
|
let mailing = get_mailing().await?;
|
||||||
|
let msg = get_message(MessageType::NewReservation).await?;
|
||||||
|
|
||||||
|
for m in emails_for_notify().await? {
|
||||||
|
mailing.send_mail(MailMessage::new(admin_mail.clone(), m, msg.clone(), reservation)).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn notify_new(uuid: Uuid) -> Result<(), AppError> {
|
||||||
|
let mailing = get_mailing().await?;
|
||||||
|
let msg = get_message(MessageType::NewReservationCust).await?;
|
||||||
|
let reservation = reservation_by_uuid(uuid).await?;
|
||||||
|
let admin_mail = admin_email().await;
|
||||||
|
|
||||||
|
if admin_mail.is_none() {
|
||||||
|
return Err(AppError::MailSendError("No admin mail".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
mailing.send_mail(MailMessage::new(admin_mail.clone().unwrap(), reservation.customer.email.clone(), msg, &reservation)).await?;
|
||||||
|
notify_new_all(admin_mail.unwrap(), &reservation).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_notify(uuid: Uuid, msg: Message) -> Result<(), AppError> {
|
||||||
|
let mailing = get_mailing().await?;
|
||||||
|
let reservation = reservation_by_uuid(uuid).await?;
|
||||||
|
let admin_mail = admin_email().await;
|
||||||
|
|
||||||
|
if admin_mail.is_none() {
|
||||||
|
return Err(AppError::MailSendError("No admin mail".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
mailing.send_mail(MailMessage::new(admin_mail.unwrap(), reservation.customer.email.clone(), msg, &reservation)).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn notify_approve(uuid: Uuid) -> Result<(), AppError> {
|
||||||
|
send_notify(uuid, get_message(MessageType::ReservationApp).await?).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn notify_cancel(uuid: Uuid) -> Result<(), AppError> {
|
||||||
|
send_notify(uuid, get_message(MessageType::ReservationCanceled).await?).await
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
@@ -206,6 +283,10 @@ pub async fn create_reservation(reservation: CrReservation) -> Result<ApiRespons
|
|||||||
|
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
|
|
||||||
|
if let Err(e) = notify_new(res_uuid).await {
|
||||||
|
warn!("Notification not send: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ApiResponse::Data(reservation.date()))
|
Ok(ApiResponse::Data(reservation.date()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +328,12 @@ pub async fn approve(uuid: String) -> Result<ApiResponse<()>, ServerFnError> {
|
|||||||
use crate::backend::data::ReservationState;
|
use crate::backend::data::ReservationState;
|
||||||
|
|
||||||
perm_check!(is_logged_in);
|
perm_check!(is_logged_in);
|
||||||
set_state(Uuid::parse_str(&uuid)?, ReservationState::Approved).await?;
|
let uuid = Uuid::parse_str(&uuid)?;
|
||||||
|
set_state(uuid, ReservationState::Approved).await?;
|
||||||
|
|
||||||
|
if let Err(e) = notify_approve(uuid).await {
|
||||||
|
warn!("Approve notification not send: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ApiResponse::Data(()))
|
Ok(ApiResponse::Data(()))
|
||||||
}
|
}
|
||||||
@@ -258,7 +344,12 @@ pub async fn cancel(uuid: String) -> Result<ApiResponse<()>, ServerFnError> {
|
|||||||
use crate::backend::data::ReservationState;
|
use crate::backend::data::ReservationState;
|
||||||
|
|
||||||
perm_check!(is_logged_in);
|
perm_check!(is_logged_in);
|
||||||
set_state(Uuid::parse_str(&uuid)?, ReservationState::Canceled).await?;
|
let uuid = Uuid::parse_str(&uuid)?;
|
||||||
|
set_state(uuid, ReservationState::Canceled).await?;
|
||||||
|
|
||||||
|
if let Err(e) = notify_cancel(uuid).await {
|
||||||
|
warn!("Cancel notification not send: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ApiResponse::Data(()))
|
Ok(ApiResponse::Data(()))
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
use leptos_actix::{extract, redirect};
|
use leptos_actix::{extract, redirect};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
|
use crate::backend::get_pool;
|
||||||
|
|
||||||
pub async fn has_admin_user(pool: &PgPool) -> Result<bool, Error> {
|
pub async fn has_admin_user(pool: &PgPool) -> Result<bool, Error> {
|
||||||
let count: (i64,) = query_as(r#"SELECT COUNT(id) FROM "user" WHERE admin = $1"#)
|
let count: (i64,) = query_as(r#"SELECT COUNT(id) FROM "user" WHERE admin = $1"#)
|
||||||
@@ -68,6 +69,36 @@ cfg_if! { if #[cfg(feature = "ssr")] {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn admin_email() -> Option<String> {
|
||||||
|
let pool = get_pool().await.ok()?;
|
||||||
|
let mail: Result<(String,), Error> = query_as(r#"SELECT email FROM "user" WHERE login = 'admin'"#)
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Ok(m) = mail {
|
||||||
|
Some(m.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emails_for_notify() -> Result<Vec<String>, ServerFnError> {
|
||||||
|
let pool = get_pool().await?;
|
||||||
|
let mails: Result<Vec<(String,)>, Error> = query_as(r#"SELECT email FROM "user" WHERE (email IS NOT NULL OR email <> '') AND get_emails = true"#)
|
||||||
|
.fetch_all(&pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(e) = mails {
|
||||||
|
if matches!(e, Error::RowNotFound) {
|
||||||
|
Ok(vec![])
|
||||||
|
} else {
|
||||||
|
Err(e.into())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(mails.unwrap().into_iter().map(|m| m.0).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
|
|||||||
+50
-1
@@ -51,12 +51,58 @@ impl Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub enum MailTransport {
|
||||||
|
Smtp,
|
||||||
|
File
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
#[derive(Deserialize, Clone)]
|
||||||
|
pub struct Mailing {
|
||||||
|
transport: MailTransport,
|
||||||
|
from: String,
|
||||||
|
path: Option<String>,
|
||||||
|
server: Option<String>,
|
||||||
|
user: Option<String>,
|
||||||
|
password: Option<String>,
|
||||||
|
tls: Option<bool>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl Mailing {
|
||||||
|
pub fn transport(&self) -> &MailTransport {
|
||||||
|
&self.transport
|
||||||
|
}
|
||||||
|
pub fn from(&self) -> &str {
|
||||||
|
&self.from
|
||||||
|
}
|
||||||
|
pub fn path(&self) -> &Option<String> {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
pub fn server(&self) -> &Option<String> {
|
||||||
|
&self.server
|
||||||
|
}
|
||||||
|
pub fn user(&self) -> &Option<String> {
|
||||||
|
&self.user
|
||||||
|
}
|
||||||
|
pub fn password(&self) -> &Option<String> {
|
||||||
|
&self.password
|
||||||
|
}
|
||||||
|
pub fn tls(&self) -> Option<bool> {
|
||||||
|
self.tls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
session: Session,
|
session: Session,
|
||||||
network: Network,
|
network: Network,
|
||||||
database: Database
|
database: Database,
|
||||||
|
mailing: Mailing
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
@@ -70,6 +116,9 @@ impl Configuration {
|
|||||||
pub fn database(&self) -> &Database {
|
pub fn database(&self) -> &Database {
|
||||||
&self.database
|
&self.database
|
||||||
}
|
}
|
||||||
|
pub fn mailing(&self) -> &Mailing {
|
||||||
|
&self.mailing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
|
|||||||
+34
-2
@@ -8,7 +8,9 @@ pub enum AppError {
|
|||||||
HourParseError,
|
HourParseError,
|
||||||
ServerError(String),
|
ServerError(String),
|
||||||
FatalError(String),
|
FatalError(String),
|
||||||
SlotParseError
|
SlotParseError,
|
||||||
|
MailAddrParseErr(String),
|
||||||
|
MailSendError(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppError {
|
impl AppError {
|
||||||
@@ -17,7 +19,9 @@ impl AppError {
|
|||||||
AppError::HourParseError => {"Hour parse error".to_string()},
|
AppError::HourParseError => {"Hour parse error".to_string()},
|
||||||
AppError::ServerError(e) => {format!("Server error: {}", e)},
|
AppError::ServerError(e) => {format!("Server error: {}", e)},
|
||||||
AppError::FatalError(e) => {format!("Fatal error: {}", e)},
|
AppError::FatalError(e) => {format!("Fatal error: {}", e)},
|
||||||
AppError::SlotParseError => {"Book slot parse error".to_string()}
|
AppError::SlotParseError => {"Book slot parse error".to_string()},
|
||||||
|
AppError::MailAddrParseErr(e) => {format!("Cannot parse email address: {}", e)},
|
||||||
|
AppError::MailSendError(e) => {format!("Cannot send email: {}", e)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,3 +52,31 @@ impl From<ParseError> for AppError {
|
|||||||
AppError::HourParseError
|
AppError::HourParseError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl From<lettre::address::AddressError> for AppError {
|
||||||
|
fn from(value: lettre::address::AddressError) -> Self {
|
||||||
|
AppError::MailAddrParseErr(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl From<lettre::error::Error> for AppError {
|
||||||
|
fn from(value: lettre::error::Error) -> Self {
|
||||||
|
AppError::MailSendError(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl From<lettre::transport::smtp::Error> for AppError {
|
||||||
|
fn from(value: lettre::transport::smtp::Error) -> Self {
|
||||||
|
AppError::MailSendError(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
impl From<lettre::transport::file::Error> for AppError {
|
||||||
|
fn from(value: lettre::transport::file::Error) -> Self {
|
||||||
|
AppError::MailSendError(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-2
@@ -51,9 +51,10 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let pool = PgPoolOptions::new()
|
let pool = PgPoolOptions::new()
|
||||||
.max_connections(10)
|
.max_connections(10)
|
||||||
.connect(&srv_conf.database().con_string()).await.unwrap();
|
.connect(&srv_conf.database().con_string()).await.unwrap();
|
||||||
|
|
||||||
migrate!().run(&pool).await.expect("could not run SQLx migrations");
|
migrate!().run(&pool).await.expect("could not run SQLx migrations");
|
||||||
|
|
||||||
|
let mailing = srv_conf.mailing().clone();
|
||||||
|
|
||||||
if let Err(e) = create_admin(&pool).await {
|
if let Err(e) = create_admin(&pool).await {
|
||||||
error!("Error while checking admin user: {:?}", e);
|
error!("Error while checking admin user: {:?}", e);
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let site_root = &leptos_options.site_root;
|
let site_root = &leptos_options.site_root;
|
||||||
|
|
||||||
App::new()
|
App::new()
|
||||||
.app_data(Data::new(AppData::new(pool.clone())))
|
.app_data(Data::new(AppData::new(pool.clone(), mailing.clone())))
|
||||||
.wrap(Authentication)
|
.wrap(Authentication)
|
||||||
.wrap(SessionMiddleware::new(
|
.wrap(SessionMiddleware::new(
|
||||||
CookieSessionStore::default(),
|
CookieSessionStore::default(),
|
||||||
|
|||||||
Reference in New Issue
Block a user