Browse Source

Change template lib to tera

main
Manos Pitsidianakis 1 week ago
parent
commit
2af8fe1b5e
  1. 522
      Cargo.lock
  2. 3
      archive-http/Cargo.toml
  3. 130
      archive-http/src/main.rs
  4. 0
      archive-http/src/templates/css.html
  5. 0
      archive-http/src/templates/footer.html
  6. 0
      archive-http/src/templates/header.html
  7. 0
      archive-http/src/templates/index.html
  8. 0
      archive-http/src/templates/list.html
  9. 4
      archive-http/src/templates/lists.html
  10. 0
      archive-http/src/templates/menu.html
  11. 36
      archive-http/src/templates/post.html
  12. 10
      archive-http/templates/post.html
  13. 35
      cli/src/main.rs
  14. 83
      core/src/config.rs
  15. 38
      core/src/db.rs
  16. 8
      core/src/db/posts.rs
  17. 22
      core/tests/creation.rs
  18. 11
      core/tests/error_queue.rs
  19. 13
      core/tests/smtp.rs
  20. 8
      docs/command.mdoc
  21. 8
      docs/mailpot.1
  22. 16
      rest-http/src/main.rs

522
Cargo.lock

@ -10,7 +10,16 @@ checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check 0.9.4",
"version_check",
]
[[package]]
name = "aho-corasick"
version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
dependencies = [
"memchr",
]
[[package]]
@ -28,50 +37,6 @@ version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "askama"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dc2a4b6d7f812d2b13d251ae792caecebd635d6401761162d4b71d5ebe1a010"
dependencies = [
"askama_derive",
"askama_escape",
"askama_shared",
]
[[package]]
name = "askama_derive"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ee2fff0f22ad5d215cace1227cd036c28e81e26206763bb837b6d0e766c87d"
dependencies = [
"askama_shared",
"nom 4.2.3",
"proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
[[package]]
name = "askama_escape"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0de942230b5beedaa9e1d64df5b76fa1c97002e4c7982897be899cccf40621d"
[[package]]
name = "askama_shared"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6dfa6b6d254fd066a8bbed9a8f913123e3f701db89216ad4f0aff04ad87718c"
dependencies = [
"askama_escape",
"humansize",
"num-traits",
"serde",
"serde_derive",
"toml 0.4.10",
]
[[package]]
name = "async-channel"
version = "1.6.1"
@ -180,9 +145,9 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -267,6 +232,15 @@ dependencies = [
"once_cell",
]
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"memchr",
]
[[package]]
name = "buf_redux"
version = "0.8.4"
@ -339,6 +313,28 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "chrono-tz"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde"
dependencies = [
"chrono",
"chrono-tz-build",
"phf",
]
[[package]]
name = "chrono-tz-build"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c"
dependencies = [
"parse-zoneinfo",
"phf",
"phf_codegen",
]
[[package]]
name = "clap"
version = "2.34.0"
@ -388,6 +384,15 @@ dependencies = [
"libc",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422f23e724af1240ec469ea1e834d87a4b59ce2efe2c6a96256b0c47e2fd86aa"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
@ -404,6 +409,12 @@ version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57"
[[package]]
name = "deunicode"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690"
[[package]]
name = "digest"
version = "0.9.0"
@ -519,7 +530,7 @@ version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc"
dependencies = [
"version_check 0.9.4",
"version_check",
]
[[package]]
@ -696,9 +707,9 @@ version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -738,7 +749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
"typenum",
"version_check 0.9.4",
"version_check",
]
[[package]]
@ -752,6 +763,30 @@ dependencies = [
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "globset"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a"
dependencies = [
"aho-corasick",
"bstr",
"fnv",
"log",
"regex",
]
[[package]]
name = "globwalk"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
dependencies = [
"bitflags",
"ignore",
"walkdir",
]
[[package]]
name = "h2"
version = "0.3.13"
@ -910,6 +945,24 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "ignore"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
dependencies = [
"crossbeam-utils",
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
"thread_local",
"walkdir",
"winapi-util",
]
[[package]]
name = "indexmap"
version = "1.9.1"
@ -1051,7 +1104,7 @@ dependencies = [
"base64",
"either",
"log",
"nom 7.1.1",
"nom",
"ternop",
]
@ -1085,7 +1138,7 @@ dependencies = [
"serde_json",
"stderrlog",
"tempfile",
"toml 0.5.9",
"toml",
"xdg",
]
@ -1131,7 +1184,7 @@ dependencies = [
"libloading",
"native-tls",
"nix",
"nom 7.1.1",
"nom",
"notify",
"serde",
"serde_derive",
@ -1239,9 +1292,10 @@ dependencies = [
name = "mpot-archives"
version = "0.1.0"
dependencies = [
"askama",
"lazy_static",
"mailpot",
"percent-encoding",
"tera",
"tokio",
"warp",
]
@ -1305,16 +1359,6 @@ dependencies = [
"memoffset",
]
[[package]]
name = "nom"
version = "4.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
dependencies = [
"memchr",
"version_check 0.1.5",
]
[[package]]
name = "nom"
version = "7.1.1"
@ -1405,9 +1449,9 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -1458,12 +1502,104 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
dependencies = [
"regex",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc7bc69c062e492337d74d59b120c274fd3d261b6bf6d3207d499b4b379c41a"
dependencies = [
"thiserror",
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b75706b9642ebcb34dab3bc7750f811609a0eb1dd8b88c2d15bf628c1c65b2"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f9272122f5979a6511a749af9db9bfc810393f63119970d7085fed1c4ea0db"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8717927f9b79515e565a64fe46c38b8cd0427e64c40680b14a7365ab09ac8d"
dependencies = [
"once_cell",
"pest",
"sha1",
]
[[package]]
name = "phf"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
dependencies = [
"siphasher",
"uncased",
]
[[package]]
name = "pin-project"
version = "1.0.11"
@ -1479,9 +1615,9 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -1528,10 +1664,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"version_check 0.9.4",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
@ -1540,18 +1676,9 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"version_check 0.9.4",
]
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
"unicode-xid",
"proc-macro2",
"quote",
"version_check",
]
[[package]]
@ -1569,22 +1696,13 @@ version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
"proc-macro2 0.4.30",
]
[[package]]
name = "quote"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
"proc-macro2 1.0.40",
"proc-macro2",
]
[[package]]
@ -1637,6 +1755,23 @@ dependencies = [
"thiserror",
]
[[package]]
name = "regex"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
@ -1794,9 +1929,9 @@ version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -1846,6 +1981,17 @@ dependencies = [
"digest 0.10.3",
]
[[package]]
name = "sha1"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "006769ba83e921b3085caa8334186b00cf92b4cb1a6cf4632fbccc8eff5c7549"
dependencies = [
"cfg-if 1.0.0",
"cpufeatures",
"digest 0.10.3",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
@ -1871,12 +2017,27 @@ dependencies = [
"libc",
]
[[package]]
name = "siphasher"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
[[package]]
name = "slab"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32"
[[package]]
name = "slug"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373"
dependencies = [
"deunicode",
]
[[package]]
name = "smallvec"
version = "1.9.0"
@ -1957,20 +2118,9 @@ source = "git+https://github.com/epilys/structopt-derive-manpage#2861b6318cfe9fc
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
]
[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
"proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -1979,8 +2129,8 @@ version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"proc-macro2",
"quote",
"unicode-ident",
]
@ -1998,6 +2148,28 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "tera"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d"
dependencies = [
"chrono",
"chrono-tz",
"globwalk",
"humansize",
"lazy_static",
"percent-encoding",
"pest",
"pest_derive",
"rand",
"regex",
"serde",
"serde_json",
"slug",
"unic-segment",
]
[[package]]
name = "termcolor"
version = "1.1.3"
@ -2037,9 +2209,9 @@ version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -2104,9 +2276,9 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -2161,15 +2333,6 @@ dependencies = [
"tracing",
]
[[package]]
name = "toml"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
dependencies = [
"serde",
]
[[package]]
name = "toml"
version = "0.5.9"
@ -2246,13 +2409,78 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81"
[[package]]
name = "uncased"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622"
dependencies = [
"version_check",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23"
dependencies = [
"unic-ucd-segment",
]
[[package]]
name = "unic-ucd-segment"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check 0.9.4",
"version_check",
]
[[package]]
@ -2288,12 +2516,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
[[package]]
name = "untrusted"
version = "0.7.1"
@ -2341,12 +2563,6 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.4"
@ -2441,9 +2657,9 @@ dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
@ -2453,7 +2669,7 @@ version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
dependencies = [
"quote 1.0.20",
"quote",
"wasm-bindgen-macro-support",
]
@ -2463,9 +2679,9 @@ version = "0.2.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
dependencies = [
"proc-macro2 1.0.40",
"quote 1.0.20",
"syn 1.0.98",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

3
archive-http/Cargo.toml

@ -16,8 +16,9 @@ name = "mpot-archives"
path = "src/main.rs"
[dependencies]
askama = "0.8"
tera = "1"
mailpot = { version = "0.1.0", path = "../core" }
percent-encoding = "2.1"
tokio = { version = "1", features = ["full"] }
warp = "0.3"
lazy_static = "*"

130
archive-http/src/main.rs

@ -25,9 +25,30 @@ pub use mailpot::errors::*;
pub use mailpot::models::*;
pub use mailpot::*;
use askama::Template;
use std::sync::Arc;
use percent_encoding::percent_decode_str;
use tera::{Context, Tera};
use warp::Filter;
lazy_static::lazy_static! {
pub static ref TEMPLATES: Tera = {
let mut tera = match Tera::new("src/templates/*") {
Ok(t) => t,
Err(e) => {
println!("Parsing error(s): {}", e);
::std::process::exit(1);
}
};
let names: Vec<_> = tera.get_template_names().collect();
println!("names: {:?}", names);
assert!(!names.is_empty());
tera.autoescape_on(vec![".html", ".sql"]);
tera
};
}
/*
#[derive(Template)]
#[template(path = "lists.html")]
struct ListsTemplate<'a> {
@ -75,72 +96,99 @@ struct PostTemplate<'a> {
_in_reply_to: Option<String>,
_references: Vec<String>,
}
*/
use warp::Filter;
#[tokio::main]
async fn main() {
let list_handler = warp::path!("lists" / i64).map(|list_pk: i64| {
let db = Database::open_or_create_db().unwrap();
let config_path = std::env::args()
.skip(1)
.next()
.expect("Expected configuration file path as first argument.");
let conf = Arc::new(Configuration::from_file(config_path).unwrap());
let conf1 = conf.clone();
let list_handler = warp::path!("lists" / i64).map(move |list_pk: i64| {
let db = Database::open_db(&conf1).unwrap();
let list = db.get_list(list_pk).unwrap().unwrap();
let months = db.months(list_pk).unwrap();
let posts = db.list_posts(list_pk, None).unwrap();
let template = ListTemplate {
title: &list.name,
list: &list,
months,
posts,
body: &list.description.clone().unwrap_or_default(),
};
let res = template.render().unwrap();
Ok(warp::reply::html(res))
let mut context = Context::new();
context.insert("title", &list.name);
context.insert("list", &list);
context.insert("months", &months);
context.insert("posts", &posts);
context.insert("body", &list.description.clone().unwrap_or_default());
Ok(warp::reply::html(
TEMPLATES.render("list.html", &context).unwrap(),
))
});
let conf2 = conf.clone();
let post_handler =
warp::path!("list" / i64 / String).map(|list_pk: i64, message_id: String| {
warp::path!("list" / i64 / String).map(move |list_pk: i64, message_id: String| {
let message_id = percent_decode_str(&message_id).decode_utf8().unwrap();
let db = Database::open_or_create_db().unwrap();
let db = Database::open_db(&conf2).unwrap();
let list = db.get_list(list_pk).unwrap().unwrap();
let posts = db.list_posts(list_pk, None).unwrap();
let post = posts
.into_iter()
.iter()
.find(|p| message_id.contains(&p.message_id))
.unwrap();
let envelope = melib::Envelope::from_bytes(post.message.as_slice(), None)
.expect("Could not parse mail");
let body = envelope.body_bytes(post.message.as_slice());
let body_text = body.text();
let template = PostTemplate {
title: &list.name,
_list: &list,
_post: post,
body: &body_text,
_from: &envelope.field_from_to_string(),
_to: &envelope.field_to_to_string(),
subject: &envelope.subject(),
_in_reply_to: envelope.in_reply_to_display().map(|r| r.to_string()),
_references: envelope
let mut context = Context::new();
context.insert("title", &list.name);
context.insert("list", &list);
context.insert("post", &post);
context.insert("posts", &posts);
context.insert("body", &body_text);
context.insert("from", &envelope.field_from_to_string());
context.insert("date", &envelope.date_as_str());
context.insert("to", &envelope.field_to_to_string());
context.insert("subject", &envelope.subject());
context.insert(
"in_reply_to",
&envelope.in_reply_to_display().map(|r| r.to_string()),
);
context.insert(
"references",
&envelope
.references()
.into_iter()
.map(|m| m.to_string())
.collect::<Vec<String>>(),
};
let res = template.render().unwrap();
Ok(warp::reply::html(res))
);
Ok(warp::reply::html(
TEMPLATES.render("post.html", &context).unwrap(),
))
});
let index_handler = warp::path::end().map(|| {
let db = Database::open_or_create_db().unwrap();
let conf3 = conf.clone();
let index_handler = warp::path::end().map(move || {
let db = Database::open_db(&conf3).unwrap();
let lists_values = db.list_lists().unwrap();
dbg!(&lists_values);
let lists = lists_values
.iter()
.map(|list| (list, &db).into())
.collect::<Vec<ListTemplate<'_>>>();
let template = ListsTemplate {
title: "mailing list archive",
description: "",
lists_len: lists.len(),
lists,
};
let res = template.render().unwrap();
Ok(warp::reply::html(res))
.map(|list| {
let mut context = Context::new();
let months = db.months(list.pk).unwrap();
let posts = db.list_posts(list.pk, None).unwrap();
context.insert("title", &list.name);
context.insert("list", &list);
context.insert("posts", &posts);
context.insert("months", &months);
context.insert("body", &list.description.as_deref().unwrap_or_default());
context.into_json()
})
.collect::<Vec<_>>();
let mut context = Context::new();
context.insert("title", "mailing list archive");
context.insert("description", "");
context.insert("lists", &lists);
Ok(warp::reply::html(
TEMPLATES.render("lists.html", &context).unwrap(),
))
});
let routes = warp::get()
.and(index_handler)

0
archive-http/templates/css.html → archive-http/src/templates/css.html

0
archive-http/templates/footer.html → archive-http/src/templates/footer.html

0
archive-http/templates/header.html → archive-http/src/templates/header.html

0
archive-http/templates/index.html → archive-http/src/templates/index.html

0
archive-http/templates/list.html → archive-http/src/templates/list.html

4
archive-http/templates/lists.html → archive-http/src/templates/lists.html

@ -1,9 +1,9 @@
{% include "header.html" %}
<div class="entry">
<p>{{lists_len}} lists</p>
<p>{{lists|length}} lists</p>
<div class="body">
{% for list in lists %}
{{ list }}
{{ list.title }}
{% endfor %}
</div>
</div>

0
archive-http/templates/menu.html → archive-http/src/templates/menu.html

36
archive-http/src/templates/post.html

@ -0,0 +1,36 @@
{% include "header.html" %}
<div class="entry">
<h1>{{subject}}</h1>
<table class="headers">
<tr>
<th scope="row">List</th>
<td>{{ list.id }}</td>
</tr>
<tr>
<th scope="row">From</th>
<td>{{ from }}</td>
</tr>
<tr>
<th scope="row">Date</th>
<td>{{ date }}</td>
</tr>
<tr>
<th scope="row">To</th>
<td>{{ to }}</td>
</tr>
<tr>
<th scope="row">Subject</th>
<td>{{ subject }}</td>
</tr>
{% if in_reply_to %}
<tr>
<th scope="row">In-Reply-To</th>
<td>{{ in_reply_to }}</td>
</tr>
{% endif %}
</table>
<div class="body">
<pre>{{body}}</pre>
</div>
</div>
{% include "footer.html" %}

10
archive-http/templates/post.html

@ -1,10 +0,0 @@
{% include "header.html" %}
<div class="entry">
<h1>{{subject}}</h1>
<div class="body">
<pre>
{{body}}
</pre>
</div>
</div>
{% include "footer.html" %}

35
cli/src/main.rs

@ -48,7 +48,7 @@ struct Opt {
/// Set config file
#[structopt(short, long, parse(from_os_str))]
#[allow(dead_code)]
config: Option<PathBuf>,
config: PathBuf,
#[structopt(flatten)]
cmd: Command,
/// Silence all output
@ -65,10 +65,6 @@ struct Opt {
#[derive(Debug, StructOpt)]
#[structopt(manpage = "docs/command.mdoc")]
enum Command {
///Prints database filesystem location
DbLocation,
///Prints default configuration file filesystem location
ConfigLocation,
///Dumps database data to STDOUT
DumpDatabase,
///Lists all registered mailing lists
@ -238,22 +234,11 @@ fn run_app(opt: Opt) -> Result<()> {
if opt.debug {
println!("DEBUG: {:?}", &opt);
}
if let Some(config_path) = opt.config.as_ref() {
let config = Configuration::from_file(&config_path)?;
config.init_with()?;
} else {
Configuration::init()?;
}
let config = Configuration::from_file(opt.config.as_path())?;
use Command::*;
let mut db = Database::open_or_create_db(&config)?;
match opt.cmd {
DbLocation => {
println!("{}", Database::db_path()?.display());
}
ConfigLocation => {
println!("{}", Configuration::default_path()?.display());
}
DumpDatabase => {
let db = Database::open_or_create_db()?;
let lists = db.list_lists()?;
let mut stdout = std::io::stdout();
serde_json::to_writer_pretty(&mut stdout, &lists)?;
@ -262,7 +247,6 @@ fn run_app(opt: Opt) -> Result<()> {
}
}
ListLists => {
let db = Database::open_or_create_db()?;
let lists = db.list_lists()?;
if lists.is_empty() {
println!("No lists found.");
@ -288,7 +272,6 @@ fn run_app(opt: Opt) -> Result<()> {
}
}
List { list_id, cmd } => {
let db = Database::open_or_create_db()?;
let list = match db.get_list_by_id(&list_id)? {
Some(v) => v,
None => {
@ -531,7 +514,6 @@ fn run_app(opt: Opt) -> Result<()> {
description,
archive_url,
} => {
let db = Database::open_or_create_db()?;
let new = db.create_list(MailingList {
pk: 0,
name,
@ -564,12 +546,15 @@ fn run_app(opt: Opt) -> Result<()> {
if opt.debug {
std::dbg!(&env);
}
let db = Database::open_or_create_db()?;
db.post(&env, input.as_bytes(), dry_run)?;
}
Err(err) if input.trim().is_empty() => {
eprintln!("Empty input, abort.");
return Err(err.into());
}
Err(err) => {
eprintln!("Could not parse message: {}", err);
let p = Configuration::save_message(input)?;
let p = config.save_message(input)?;
eprintln!("Message saved at {}", p.display());
return Err(err.into());
}
@ -577,7 +562,6 @@ fn run_app(opt: Opt) -> Result<()> {
}
ErrorQueue { cmd } => match cmd {
ErrorQueueCommand::List => {
let db = Database::open_or_create_db()?;
let errors = db.error_queue()?;
if errors.is_empty() {
println!("Error queue is empty.");
@ -595,7 +579,6 @@ fn run_app(opt: Opt) -> Result<()> {
}
}
ErrorQueueCommand::Print { index, json } => {
let db = Database::open_or_create_db()?;
let mut errors = db.error_queue()?;
if !index.is_empty() {
errors.retain(|el| index.contains(&el.pk()));
@ -613,7 +596,6 @@ fn run_app(opt: Opt) -> Result<()> {
}
}
ErrorQueueCommand::Delete { index, quiet } => {
let mut db = Database::open_or_create_db()?;
let mut errors = db.error_queue()?;
if !index.is_empty() {
errors.retain(|el| index.contains(&el.pk()));
@ -639,7 +621,6 @@ fn run_app(opt: Opt) -> Result<()> {
list_id,
mut maildir_path,
} => {
let db = Database::open_or_create_db()?;
let list = match db.get_list_by_id(&list_id)? {
Some(v) => v,
None => {

83
core/src/config.rs

@ -24,9 +24,6 @@ use std::io::{Read, Write};
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
thread_local!(pub static CONFIG: RefCell<Configuration> = RefCell::new(Configuration::new()));
thread_local!(static CONFIG_INIT: Cell<bool> = Cell::new(false));
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "type", content = "value")]
pub enum SendMail {
@ -40,33 +37,24 @@ pub struct Configuration {
#[serde(default = "default_storage_fn")]
pub storage: String,
pub db_path: PathBuf,
}
impl Default for Configuration {
fn default() -> Self {
Self::new()
}
pub data_path: PathBuf,
}
impl Configuration {
pub(crate) fn new() -> Self {
/*
pub fn new(db_path: impl Into<PathBuf>) -> Self {
let db_path = db_path.into();
Configuration {
send_mail: SendMail::ShellCommand("/usr/bin/false".to_string()),
storage: "sqlite3".into(),
db_path: ".".into(),
data_path: db_path
.parent()
.map(Path::to_path_buf)
.unwrap_or_else(|| db_path.clone()),
db_path,
}
}
pub fn init_with(self) -> Result<()> {
CONFIG.with(|f| {
*f.borrow_mut() = self;
});
CONFIG_INIT.with(|f| {
f.set(true);
});
Ok(())
}
*/
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
let path = path.as_ref();
@ -81,27 +69,12 @@ impl Configuration {
Ok(config)
}
pub fn init() -> Result<()> {
if CONFIG_INIT.with(|f| f.get()) {
return Ok(());
}
let mut path =
xdg::BaseDirectories::with_prefix("mailpot")?.place_config_file("config.toml")?;
if !path.exists() {
return Err(format!("Configuration file {} doesn't exist", path.display()).into());
}
if path.starts_with("~") {
path = Path::new(&std::env::var("HOME").context("No $HOME set.")?)
.join(path.strip_prefix("~").context("Internal error while getting default database path: path starts with ~ but rust couldn't strip_refix(\"~\"")?);
}
let config: Configuration = Self::from_file(&path)?;
config.init_with()
pub fn data_directory(&self) -> &Path {
self.data_path.as_path()
}
pub fn data_directory() -> Result<PathBuf> {
Ok(xdg::BaseDirectories::with_prefix("mailpot")?
.get_data_home()
.canonicalize()?)
pub fn db_path(&self) -> &Path {
self.db_path.as_path()
}
pub fn default_path() -> Result<PathBuf> {
@ -114,10 +87,13 @@ impl Configuration {
Ok(result)
}
pub fn save_message_to_path(msg: &str, mut path: PathBuf) -> Result<PathBuf> {
let now = Local::now().timestamp();
path.push(format!("{}-failed.eml", now));
pub fn save_message_to_path(&self, msg: &str, mut path: PathBuf) -> Result<PathBuf> {
if path.is_dir() {
let now = Local::now().timestamp();
path.push(format!("{}-failed.eml", now));
}
debug_assert!(path != self.db_path());
let mut file = std::fs::File::create(&path)?;
let metadata = file.metadata()?;
let mut permissions = metadata.permissions();
@ -129,23 +105,8 @@ impl Configuration {
Ok(path)
}
pub fn save_message(msg: String) -> Result<PathBuf> {
match Configuration::data_directory()
.and_then(|path| Self::save_message_to_path(&msg, path))
{
Ok(p) => return Ok(p),
Err(err) => {
eprintln!("{}", err);
}
};
match Self::save_message_to_path(&msg, PathBuf::from(".")) {
Ok(p) => return Ok(p),
Err(err) => {
eprintln!("{}", err);
}
}
let temp_path = std::env::temp_dir();
Self::save_message_to_path(&msg, temp_path)
pub fn save_message(&self, msg: String) -> Result<PathBuf> {
self.save_message_to_path(&msg, self.data_directory().to_path_buf())
}
}

38
core/src/db.rs

@ -17,6 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use super::Configuration;
use super::*;
use crate::ErrorKind::*;
use melib::Envelope;
@ -25,13 +26,14 @@ use rusqlite::Connection as DbConnection;
use rusqlite::OptionalExtension;
use std::convert::TryFrom;
use std::io::Write;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
const DB_NAME: &str = "current.db";
pub struct Database {
pub connection: DbConnection,
conf: Configuration,
}
mod error_queue;
@ -42,22 +44,18 @@ mod members;
pub use members::*;
impl Database {
pub fn db_path() -> Result<PathBuf> {
Ok(crate::config::CONFIG.with(|c| c.borrow().db_path.clone()))
}
pub fn open_db(db_path: PathBuf) -> Result<Self> {
if !db_path.exists() {
pub fn open_db(conf: &Configuration) -> Result<Self> {
if !conf.db_path.exists() {
return Err("Database doesn't exist".into());
}
Ok(Database {
connection: DbConnection::open(&db_path.to_str().unwrap())?,
conf: conf.clone(),
connection: DbConnection::open(&conf.db_path.to_str().unwrap())?,
})
}
pub fn open_or_create_db() -> Result<Self> {
crate::config::Configuration::init()?;
let mut db_path = Self::db_path()?;
pub fn open_or_create_db(conf: &Configuration) -> Result<Self> {
let mut db_path = conf.db_path.to_path_buf();
if db_path.is_dir() {
db_path.push(DB_NAME);
}
@ -100,11 +98,14 @@ impl Database {
let conn = DbConnection::open(&db_path.to_str().unwrap())?;
Ok(Database { connection: conn })
Ok(Database {
conf: conf.clone(),
connection: conn,
})
}
pub fn load_archives(&mut self) -> Result<&mut Self> {
let archives_path = crate::config::CONFIG.with(|c| c.borrow().db_path.clone());
pub fn load_archives(&mut self, conf: &Configuration) -> Result<&mut Self> {
let archives_path = conf.data_path.clone();
let mut stmt = self.connection.prepare("ATTACH ? AS ?;")?;
for archive in std::fs::read_dir(&archives_path)? {
let archive = archive?;
@ -232,7 +233,7 @@ impl Database {
pub fn remove_list_policy(&self, list_pk: i64, policy_pk: i64) -> Result<()> {
let mut stmt = self
.connection
.prepare("DELETE FROM post_policy WHERE pk = ? AND list_pk = ?;")?;
.prepare("DELETE FROM post_policy WHERE pk = ? AND list = ?;")?;
stmt.execute(rusqlite::params![&policy_pk, &list_pk,])?;
trace!("remove_list_policy {} {}.", list_pk, policy_pk);
@ -240,6 +241,13 @@ impl Database {
}
pub fn set_list_policy(&self, list_pk: i64, policy: PostPolicy) -> Result<DbVal<PostPolicy>> {
if !(policy.announce_only || policy.subscriber_only || policy.approval_needed) {
return Err(
"Cannot add empty policy. Having no policies is probably what you want to do."
.into(),
);
}
let mut stmt = self.connection.prepare("INSERT OR REPLACE INTO post_policy(list, announce_only, subscriber_only, approval_needed) VALUES (?, ?, ?, ?) RETURNING *;")?;
let ret = stmt.query_row(
rusqlite::params![

8
core/src/db/posts.rs

@ -119,11 +119,7 @@ impl Database {
return Ok(());
}
let mut configuration = crate::config::Configuration::new();
crate::config::CONFIG.with(|f| {
configuration = f.borrow().clone();
});
trace!("Configuration is {:#?}", &configuration);
trace!("Configuration is {:#?}", &self.conf);
use crate::mail::{ListContext, Post, PostAction};
for mut list in lists {
trace!("Examining list {}", list.list_id());
@ -161,7 +157,7 @@ impl Database {
trace!("recipients: {:?}", &recipients);
if let crate::config::SendMail::Smtp(ref smtp_conf) =
&configuration.send_mail
&self.conf.send_mail
{
let smtp_conf = smtp_conf.clone();
use melib::futures;

22
core/tests/creation.rs

@ -1,4 +1,4 @@
use mailpot::{models::*, Configuration, Database};
use mailpot::{models::*, Configuration, Database, SendMail};
use tempfile::TempDir;
#[test]