diff --git a/Cargo.lock b/Cargo.lock index 3056545..569ca04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,30 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5" -dependencies = [ - "actix-rt", - "actix_derive", - "bitflags", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", -] - [[package]] name = "actix-codec" version = "0.5.1" @@ -53,7 +29,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", + "ahash 0.8.7", "base64", "bitflags", "brotli", @@ -94,9 +70,9 @@ dependencies = [ [[package]] name = "actix-multipart" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e" +checksum = "3b960e2aea75f49c8f069108063d12a48d329fc8b60b786dfc7552a9d5918d2d" dependencies = [ "actix-multipart-derive", "actix-utils", @@ -119,15 +95,15 @@ dependencies = [ [[package]] name = "actix-multipart-derive" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7" +checksum = "0a0a77f836d869f700e5b47ac7c3c8b9c8bc82e4aec861954c6198abee3ebd4d" dependencies = [ "darling", "parse-size", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.43", ] [[package]] @@ -167,7 +143,7 @@ dependencies = [ "futures-util", "mio", "num_cpus", - "socket2", + "socket2 0.4.9", "tokio", "tracing", ] @@ -229,7 +205,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.4.9", "time", "url", ] @@ -246,17 +222,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "actix_derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "adler" version = "1.0.2" @@ -276,21 +241,22 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] @@ -310,6 +276,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "async-channel" version = "1.8.0" @@ -330,7 +302,7 @@ dependencies = [ "async-lock", "async-task", "concurrent-queue", - "fastrand", + "fastrand 1.9.0", "futures-lite", "slab", ] @@ -366,7 +338,7 @@ dependencies = [ "polling", "rustix", "slab", - "socket2", + "socket2 0.4.9", "waker-fn", ] @@ -454,7 +426,7 @@ dependencies = [ "async-lock", "async-task", "atomic-waker", - "fastrand", + "fastrand 1.9.0", "futures-lite", "log", ] @@ -516,6 +488,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chumsky" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eebd66744a15ded14960ab4ccdbfb51ad3b81f51f3f04a80adac98c985396c9" +dependencies = [ + "hashbrown 0.14.3", + "stacker", +] + [[package]] name = "concurrent-queue" version = "2.2.0" @@ -576,21 +558,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" dependencies = [ "cfg-if", ] @@ -605,21 +577,11 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - [[package]] name = "darling" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -627,27 +589,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 1.0.109", + "syn 2.0.43", ] [[package]] name = "darling_macro" -version = "0.14.4" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 1.0.109", + "syn 2.0.43", ] [[package]] @@ -673,6 +635,22 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "email-encoding" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfb21b9878cf7a348dcb8559109aabc0ec40d69924bd706fa5149846c4fef75" +dependencies = [ + "base64", + "memchr", +] + +[[package]] +name = "email_address" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112" + [[package]] name = "encoding_rs" version = "0.8.32" @@ -731,6 +709,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "flate2" version = "1.0.26" @@ -764,9 +748,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] @@ -825,7 +809,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -842,7 +826,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", ] [[package]] @@ -933,6 +917,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash 0.8.7", + "allocator-api2", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -948,6 +942,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +[[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]] name = "http" version = "0.2.9" @@ -1005,7 +1010,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -1033,9 +1038,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1048,7 +1053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1135,10 +1140,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "libc" -version = "0.2.144" +name = "lettre" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f5aaf628956b6b0852e12ac3505d20d7a12ecc1e32d5ea921f002af4a74036a5" +dependencies = [ + "base64", + "chumsky", + "email-encoding", + "email_address", + "fastrand 2.0.1", + "futures-util", + "hostname", + "httpdate", + "idna", + "mime", + "native-tls", + "nom", + "quoted_printable", + "socket2 0.5.5", + "tokio", + "url", +] + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linux-raw-sys" @@ -1176,19 +1205,44 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" dependencies = [ - "cfg-if", "value-bag", ] [[package]] -name = "memchr" -version = "2.5.0" +name = "markup" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "74a887ad620fe1022257343ac77fcdd3720e92888e1b2e66e1b7a4707f453898" +dependencies = [ + "markup-proc-macro", +] + +[[package]] +name = "markup-proc-macro" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab6ee21fd1855134cacf2f41afdf45f1bc456c7d7f6165d763b4647062dd2be" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "mime" @@ -1206,6 +1260,12 @@ dependencies = [ "unicase", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1227,24 +1287,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "log", - "memchr", - "mime", - "spin", - "version_check", -] - [[package]] name = "native-tls" version = "0.2.11" @@ -1263,6 +1305,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num_cpus" version = "1.15.0" @@ -1275,9 +1327,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" @@ -1302,7 +1354,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", ] [[package]] @@ -1366,9 +1418,9 @@ checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" @@ -1412,22 +1464,37 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] [[package]] -name = "quote" -version = "1.0.28" +name = "psm" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] +[[package]] +name = "quoted_printable" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79ec282e887b434b68c18fe5c121d38e72a5cf35119b59e54ec5b992ea9c8eb0" + [[package]] name = "rand" version = "0.8.5" @@ -1478,9 +1545,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", @@ -1489,9 +1568,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" @@ -1560,6 +1639,16 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "sanitize-filename" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ed72fbaf78e6f2d41744923916966c4fbe3d7c74e3037a8ee482f1115572603" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "schannel" version = "0.1.21" @@ -1688,10 +1777,27 @@ dependencies = [ ] [[package]] -name = "spin" -version = "0.9.8" +name = "socket2" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[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]] name = "strsim" @@ -1712,9 +1818,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.18" +version = "2.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" dependencies = [ "proc-macro2", "quote", @@ -1728,7 +1834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", - "fastrand", + "fastrand 1.9.0", "redox_syscall 0.3.5", "rustix", "windows-sys 0.45.0", @@ -1747,7 +1853,6 @@ dependencies = [ name = "tfcconnection" version = "0.1.0" dependencies = [ - "actix", "actix-multipart", "actix-rt", "actix-web", @@ -1755,10 +1860,14 @@ dependencies = [ "env_logger", "futures", "futures-util", - "multer", + "lettre", + "log", + "markup", "reqwest", + "sanitize-filename", "serde", "serde_json", + "uuid", ] [[package]] @@ -1816,7 +1925,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "windows-sys 0.48.0", ] @@ -1915,9 +2024,9 @@ dependencies = [ [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -1925,14 +2034,16 @@ dependencies = [ ] [[package]] -name = "value-bag" -version = "1.0.0-alpha.9" +name = "uuid" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check", -] +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" + +[[package]] +name = "value-bag" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ce5bb364b23e66b528d03168df78b38c0f7b6fe17386928f29d5ab2e7cb2f7" [[package]] name = "vcpkg" @@ -1989,7 +2100,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", "wasm-bindgen-shared", ] @@ -2023,7 +2134,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn 2.0.43", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2231,6 +2342,26 @@ dependencies = [ "winapi", ] +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.43", +] + [[package]] name = "zstd" version = "0.12.3+zstd.1.5.2" @@ -2259,4 +2390,4 @@ dependencies = [ "cc", "libc", "pkg-config", -] \ No newline at end of file +] diff --git a/Cargo.toml b/Cargo.toml index ca15826..2f25970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,8 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -multer = "2.1.0" -actix = "0.13.0" actix-rt = "2.8.0" actix-web = "4.3.1" env_logger = "0.10.0" @@ -15,6 +13,11 @@ reqwest = { version = "0.11.18", features = ["json", "multipart"] } serde = "1.0.163" serde_json = "1.0.96" async-std = "1.12.0" -actix-multipart = "0.6.0" +actix-multipart = "0.6.1" futures = "0.3.28" -futures-util = "0.3.28" \ No newline at end of file +futures-util = "0.3.28" +log = "0.4.20" +uuid = "1.6.1" +sanitize-filename = "0.5.0" +lettre = { version = "0.11.3", features = ["smtp-transport"] } +markup = "0.15.0" diff --git a/content/health-form.md b/content/health-form.md index 034ee7f..b77ecae 100644 --- a/content/health-form.md +++ b/content/health-form.md @@ -7,4 +7,6 @@ sharingLinks: false --- Here you can fill out your health form in order to go to larger TFC events like ice skating, camp, SPLASH, and mission trip! If you've already filled out a form in May, then you won't need another until the next May! The current active health form is from {{< health-form-year >}} +However, if you are going on mission trip, you'll need to fill this out for sure, since any you've previously filled out will have expired. + {{< health-form >}} diff --git a/content/mt-form.md b/content/mt-form.md index dc3f76e..2c77a05 100644 --- a/content/mt-form.md +++ b/content/mt-form.md @@ -19,7 +19,7 @@ Requirements for this team are a flexible attitude and a willingness to do hands - Estimated Support Goal of $850-$950 -## Puerto Escondido, Mexico - *May 31 - June 9 - Highschool only +## Puerto Escondido, Mexico - *June 2 - 9 - Highschool only This trip is designed for students who have a desire to be used by Jesus to draw others into a relationship with Him and they will be trained to go with the Gospel as His ambassadors. We will be working with the ministry of Roca Blanca Mission Base in Puerto Escondido, Mexico. There are a variety of ways to serve this ministry, we might lead a VBS, work in their orphanage, assist with village ministry, work on building projects, or possibly help deliver food or clothing. Requirements for this team are a willingness and desire to share the gospel of Jesus verbally, diff --git a/flake.lock b/flake.lock index 2380cc6..385a61c 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1685518550, - "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=", + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "owner": "numtide", "repo": "flake-utils", - "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1685383865, - "narHash": "sha256-3uQytfnotO6QJv3r04ajSXbEFMII0dUtw0uqYlZ4dbk=", + "lastModified": 1704194953, + "narHash": "sha256-RtDKd8Mynhe5CFnVT8s0/0yqtWFMM9LmCzXv/YKxnq4=", "owner": "nixos", "repo": "nixpkgs", - "rev": "5e871d8aa6f57cc8e0dc087d1c5013f6e212b4ce", + "rev": "bd645e8668ec6612439a9ee7e71f7eac4099d4f6", "type": "github" }, "original": { diff --git a/layouts/shortcodes/health-form-year.html b/layouts/shortcodes/health-form-year.html index a143088..72f502b 100644 --- a/layouts/shortcodes/health-form-year.html +++ b/layouts/shortcodes/health-form-year.html @@ -1,2 +1,2 @@ -{{ time.Format "Jan 2006" "2022-05-01" }} - -{{ time.Format "Jan 2006" "2023-05-01" }}. +{{ time.Format "Jan 2006" "2023-05-01" }} - +{{ time.Format "Jan 2006" "2024-05-01" }}. diff --git a/layouts/shortcodes/health-form.html b/layouts/shortcodes/health-form.html index 0ce2abe..88863f4 100644 --- a/layouts/shortcodes/health-form.html +++ b/layouts/shortcodes/health-form.html @@ -69,8 +69,8 @@ // For use in dev // Can now start using this in production IF, // I get the server running on the server - let base = "https://api.tfcconnection.org/health-form"; - /* let base = "http://localhost:4242/health-form"; */ + /* let base = "https://api.tfcconnection.org/health-form"; */ + let base = "http://localhost:4242/health-form"; fetch(base, { method: "POST", body: data @@ -141,6 +141,18 @@ document.getElementById('warning-insurance').style.margin = '0'; document.getElementById('warning-policy').style.margin = '0'; document.getElementById('warning-image').style.margin = '0'; + + // Prefill form based from MT form + document.getElementById('firstname').value = firstName; + document.getElementById('lastname').value = lastName; + document.getElementById('parentfirstname').value = parentFirstName; + document.getElementById('parentlastname').value = parentLastName; + document.getElementById('birthdate').value = birthdate; + document.getElementById('street').value = streetP; + document.getElementById('city').value = cityP; + document.getElementById('state').value = stateP; + document.getElementById('zip').value = zipP; + document.getElementById('cellphone').value = parentPhone; } document.addEventListener('DOMContentLoaded', process); @@ -169,16 +181,28 @@ }; document.addEventListener('DOMContentLoaded', dated); - const myUrl = new URL(window.location.toLocaleString()); - const mtRegistration = myUrl.searchParams.get('mtregistration'); - const registration = myUrl.searchParams.get('registration'); + const params = new URL(window.location.toLocaleString()).searchParams; + const mtRegistration = params.get('mtregistration'); + const registration = params.get('registration'); + + const firstName = params.get('firstName'); + const lastName = params.get('lastName'); + const parentFirstName = params.get('parentFirstName'); + const parentLastName = params.get('parentLastName'); + const birthdate = params.get('birthdate'); + const streetP = params.get('street'); + const cityP = params.get('city'); + const stateP = params.get('state'); + const zipP = params.get('zip'); + const parentPhone = params.get('parentPhone'); + console.log(mtRegistration);
-

2023-2024 Health Form

+

2024-2025 Health Form


diff --git a/layouts/shortcodes/mt-form.html b/layouts/shortcodes/mt-form.html index fb66938..7c2b194 100644 --- a/layouts/shortcodes/mt-form.html +++ b/layouts/shortcodes/mt-form.html @@ -21,29 +21,21 @@ }).then((res) => { console.log(res); if (res.ok) { - //var payment = document.getElementById('registration').value; - //window.location.href = '/mt-health-form?mtregistration=' + payment; + var payment = document.getElementById('registration').value; + window.location.href = '/mt-health-form?mtregistration=' + payment + + "&firstName=" + data.get('firstname') + + "&lastName=" + data.get('lastname') + + "&parentFirstName=" + data.get('parentfirstname') + + "&parentLastName=" + data.get('parentlastname') + + "&birthdate=" + data.get('birthdate') + + "&street=" + data.get('street') + + "&city=" + data.get('city') + + "&state=" + data.get('state') + + "&zip=" + data.get('zip') + + "&parentPhone=" + data.get('parentphone'); console.log(res); } }); - - /* var xhr = new XMLHttpRequest(); - * xhr.onreadystatechange = function() { - * if (this.readyState == 4 && this.status == 200) { - * // Logic directing where to send the user after form submission based on results. - * // This is how to send them. window.location.href = '/thankyou/'; - - * var payment = document.getElementById('registration').value; - * window.location.href = '/mt-health-form?mtregistration=' + payment; - * // Need to eventually get the user here: https://secure.myvanco.com/L-Z772/campaign/C-13DM3 - * } - * }; */ - /* xhr.open("POST", "https://n8n.tfcconnection.org/webhook/mt-application"); */ - /* xhr.open("POST", "https://n8n.tfcconnection.org/webhook/mt-application"); - * xhr.send(data); - * console.log(data); - * console.log("Hallo!"); */ - /* return false; */ } function calculate_age(dob) { @@ -139,8 +131,8 @@ class="flex-auto form-input {{ $formClasses }}">
- - Parent phone +
diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..98fecb8 --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1 @@ +pub mod mt_form; diff --git a/src/api/mt_form.rs b/src/api/mt_form.rs new file mode 100644 index 0000000..2d2a74b --- /dev/null +++ b/src/api/mt_form.rs @@ -0,0 +1,526 @@ +use std::fs; + +use actix_multipart::form::{tempfile::TempFile, text::Text, MultipartForm}; +use actix_web::{post, HttpResponse}; +use lettre::{ + message::{header::ContentType, Attachment, MultiPart}, + transport::smtp::authentication::{Credentials, Mechanism}, + Message, SmtpTransport, Transport, +}; + +#[derive(Debug, MultipartForm, Default)] +struct MtForm { + #[multipart(rename = "firstname")] + first_name: Option>, + #[multipart(rename = "lastname")] + last_name: Option>, + #[multipart(rename = "parentfirstname")] + parent_first_name: Option>, + #[multipart(rename = "parentlastname")] + parent_last_name: Option>, + birthdate: Option>, + gender: Option>, + street: Option>, + city: Option>, + state: Option>, + zip: Option>, + cellphone: Option>, + parentphone: Option>, + email: Option>, + parentemail: Option>, + school: Option>, + grade: Option>, + #[multipart(rename = "pastorfirstname")] + pastor_first_name: Option>, + #[multipart(rename = "pastorlastname")] + pastor_last_name: Option>, + #[multipart(rename = "churchattendance")] + church_attendance: Option>, + #[multipart(rename = "tfcgroup")] + tfc_group: Option>, + shirt: Option>, + trip: Option>, + #[multipart(rename = "tripnotes")] + trip_notes: Option>, + #[multipart(rename = "relationship-with-jesus")] + relationship_with_jesus: Option>, + #[multipart(rename = "testimony")] + testimony: Option>, + #[multipart(rename = "involvement-with-group")] + involvement_with_group: Option>, + #[multipart(rename = "reasons-for-trip-choice")] + reasons: Option>, + strengths: Option>, + weaknesses: Option>, + #[multipart(rename = "previous-trip-info")] + previous_trip_info: Option>, + #[multipart(rename = "attitude-torward-work")] + attitude: Option>, + #[multipart(rename = "relevant-notes")] + relevant_notes: Option>, + #[multipart(rename = "final-agreement")] + final_agreement: Option>, + registration: Option>, + #[multipart(rename = "image")] + file: Option, +} + +#[post("/mt-form")] +pub async fn mt_form(MultipartForm(form): MultipartForm) -> HttpResponse { + let first = form.first_name.as_ref().unwrap().0.clone(); + let last = form.last_name.as_ref().unwrap().0.clone(); + let email_subject = format!("{} {} signed up for mission trip!", first, last); + let filename_noext = String::from(format!("{}_{}", first, last)); + let parent = format!( + "{} {}", + form.parent_first_name.as_ref().unwrap().0.clone(), + form.parent_last_name.as_ref().unwrap().0.clone() + ); + let birthdate = form + .birthdate + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let gender = form + .gender + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let street = form + .street + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let city = form + .city + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let state = form + .state + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let zip = form.zip.as_ref().unwrap_or(&Text { 0: 0 }).0.clone(); + let cellphone = form + .cellphone + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let parentphone = form + .parentphone + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let email = form + .email + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let parentemail = form + .parentemail + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let school = form + .school + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let grade = form + .grade + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let pastor = format!( + "{} {}", + form.pastor_first_name + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(), + form.pastor_last_name + .as_ref() + .unwrap_or(&Text { + 0: String::from("") + }) + .0 + .clone() + ); + let church_attendance = form + .church_attendance + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let tfc_group = form + .tfc_group + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let shirt = form + .shirt + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let trip = form + .trip + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let trip_notes = form + .trip_notes + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let relationship = form + .relationship_with_jesus + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let testimony = form + .testimony + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let involvement = form + .involvement_with_group + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let reasons = form + .reasons + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let strengths = form + .strengths + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let weaknesses = form + .weaknesses + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let previous_trip = form + .previous_trip_info + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let attitude = form + .attitude + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let relevant = form + .relevant_notes + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let final_agreement = form + .final_agreement + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + let registration = form + .registration + .as_ref() + .unwrap_or(&Text { + 0: String::from(""), + }) + .0 + .clone(); + log::info!("{first} {last} signed up for mission trip!"); + let email = markup::new! { + @markup::doctype() + html { + head { + title { @format!("{} {} signed up for mission trip!", first, last) } + style { + "table { border-collapse: collapse; width: 100% }" + "td, th { padding: 8px }" + "td { text-align: left; width: 70%; word-wrap: break-word }" + "th { text-align: right; border-right: 1px solid #ddd }" + "tr { border-bottom: 1px solid #ddd }" + "h1 { text-align: center }" + } + } + body { + h1 { @format!("Mission trip form for {} {}!", first, last) } + hr; + table { + tr { + th { "Name" } + td { @format!("{} {}", first, last) } + } + tr { + th { "Parent" } + td { @parent } + } + tr { + th { "Birthdate" } + td { @birthdate } + } + tr { + th { "Gender" } + td { @gender } + } + tr { + th { "Street" } + td { @street } + } + tr { + th { "City" } + td { @city } + } + tr { + th { "State" } + td { @state } + } + tr { + th { "Zip" } + td { @zip } + } + tr { + th { "Phone" } + td { @cellphone } + } + tr { + th { "Parent Phone" } + td { @parentphone } + } + tr { + th { "Email" } + td { @email } + } + tr { + th { "Parent Email" } + td { @parentemail } + } + tr { + th { "School" } + td { @school } + } + tr { + th { "Grade" } + td { @grade } + } + tr { + th { "Pastor" } + td { @pastor } + } + tr { + th { "Church Attendance" } + td { @church_attendance } + } + tr { + th { "TFC Group" } + td { @tfc_group } + } + tr { + th { "T-Shirt Size" } + td { @shirt } + } + tr { + th { "Trip Choice" } + td { @trip } + } + tr { + th { "Extra Trip Notes" } + td { @trip_notes } + } + tr { + th { "Relationship with Jesus" } + td { @relationship } + } + tr { + th { "Testimony" } + td { @testimony } + } + tr { + th { "Involvement with TFC or Youth Group" } + td { @involvement } + } + tr { + th { "Reasons for trip choice" } + td { @reasons } + } + tr { + th { "Strengths" } + td { @strengths } + } + tr { + th { "Weaknesses" } + td { @weaknesses } + } + tr { + th { "Previous Trips" } + td { @previous_trip } + } + tr { + th { "Attitude Torward Work" } + td { @attitude } + } + tr { + th { "Other Relevant Info" } + td { @relevant } + } + tr { + th { "Final Agreement" } + td { @final_agreement } + } + tr { + th { "Registration" } + td { @registration } + } + } + } + } + }; + let mut path: Option = Some(String::from("")); + let mut file_exists = false; + log::info!("{:?}", form); + log::info!("{:?}", file_exists); + if let Some(f) = form.file { + if let Some(file) = f.file_name { + if let Some(ext) = file.rsplit(".").next() { + path = Some(format!("./tmp/{}.{}", filename_noext, ext)); + } else { + path = Some(format!("./tmp/{}", file)); + } + // let path = format!("./tmp/{}", file); + log::info!("saving to {}", path.clone().unwrap()); + match f.file.persist(path.clone().unwrap()) { + Ok(f) => { + log::info!("{:?}", f); + if f.metadata().unwrap().len() > 0 { + file_exists = true; + } + } + Err(e) => log::info!("{:?}: Probably a missing image", e), + } + } + } + + let multi = if file_exists { + let filebody = fs::read(path.clone().unwrap_or_default()); + let content_type = ContentType::parse("image/jpg").unwrap(); + let attachment = + Attachment::new(path.unwrap_or_default()).body(filebody.unwrap(), content_type); + log::info!("{:?}", attachment); + MultiPart::alternative_plain_html(String::from("Testing"), email.to_string()) + .singlepart(attachment) + } else { + MultiPart::alternative_plain_html(String::from("Testing"), email.to_string()) + }; + + if let Ok(m) = Message::builder() + .from( + "TFC ADMIN " + .parse() + .unwrap(), + ) + .to("Chris Cochrun ".parse().unwrap()) + .to("Ethan Rose ".parse().unwrap()) + .subject(email_subject) + .multipart(multi) + { + let sender = SmtpTransport::relay("mail.tfcconnection.org") + .ok() + .unwrap() + .credentials(Credentials::new( + "no-reply@mail.tfcconnection.org".to_owned(), + "r9f36mNZFtiW4f".to_owned(), + )) + .authentication(vec![Mechanism::Plain]) + .build(); + match sender.send(&m) { + Ok(res) => log::info!("{:?}", res), + Err(e) => log::info!("{e}"), + } + } else { + log::info!("Email incorrect"); + } + + HttpResponse::Ok().body("hi") +} diff --git a/src/main.lisp b/src/main.lisp index 0d14d5f..2f4d5de 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -283,32 +283,94 @@ with the image attached to us" (uiop:println form) (let ((first-name (cdr (assoc "firstname" form :test 'string=))) (last-name (cdr (assoc "lastname" form :test 'string=)))) - (cl-smtp:send-email - "mail.tfcconnection.org" - "no-reply@mail.tfcconnection.org" - '("chris@tfcconnection.org" "chris@cochrun.xyz") - (format nil "~a ~a filled out a Mission Trip Form!" first-name last-name) - (format nil "Mission Trip Form for ~a ~a" first-name last-name) - :display-name "TFC ADMIN" - :ssl :tls - :authentication '(:login "no-reply@mail.tfcconnection.org" "r9f36mNZFtiW4f") - :attachments attachment - :html-message - (with-html-string - (:doctype) - (:html - (:head (:title "TFC Mission Trip Form") - (:style (apply #'lass:compile-and-write *mail-css*))) - (:body - (:h1 (format nil "Mission Trip Form for ~a ~a" first-name last-name)) - (:hr) - (:table - (loop for row in form - do (:tr - (:th (car row)) - (:td (trim-whitespace - (cdr row))))))))))) - (uiop:println "Mail sent!")) + (not (cl-smtp:send-email + "mail.tfcconnection.org" + "no-reply@mail.tfcconnection.org" + "chris@cochrun.xyz" + (format nil "~a ~a filled out a Mission Trip Form!" first-name last-name) + (format nil "Mission Trip Form for ~a ~a" first-name last-name) + :display-name "TFC ADMIN" + :ssl :tls + :authentication '(:login "no-reply@mail.tfcconnection.org" "r9f36mNZFtiW4f") + :attachments attachment + :html-message + (with-html-string + (:doctype) + (:html + (:head (:title "TFC Mission Trip Form") + (:style (apply #'lass:compile-and-write *mail-css*))) + (:body + (:h1 (format nil "Mission Trip Form for ~a ~a" first-name last-name)) + (:hr) + (:table + (loop for row in form + do (:tr + (:th (trim-whitespace (car row))) + (:td (trim-whitespace + (cdr row))))))))))))) + +(cl-smtp:send-email + "mail.tfcconnection.org" + "no-reply@mail.tfcconnection.org" + "chris@cochrun.xyz" + (format nil "~a ~a filled out a Mission Trip Form!" "Chris" "Ccohrun") + "hi" + :html-message + (let ((form '(("age" . "150") + ("registration" . "later") + ("final-agreement" . "yes") + ("relevant-notes" . "") + ("attitude-toward-work" . "") + ("previous-trip-info" . "") + ("weaknesses" . "") + ("strengths" . "") + ("reasons-for-trip-choice" . "") + ("involvement-with-group" . "") + ("testimony" . "") + ("relationship-with-jesus" . "") + ("tripnotes" . "") + ("trip" . "New Mexico") + ("shirt" . "small") + ("tfcgroup" . "Phillipsburg") + ("churchattendanceother" . "") + ("churchattendance" . "yes") + ("church" . "") + ("pastorphone" . "9991112222") + ("pastorlastname" . "The White") + ("pastorfirstname" . "Gandalf") + ("grade" . "sophomore") + ("school" . "A cool one") + ("parentemail" . "bilbosmells@braggins.xyz") + ("email" . "chris@cochrun.xyz") + ("parentphone" . "8889990000") + ("cellphone" . "7853021664") + ("zip" . "67661") + ("state" . "Middle Earth") + ("city" . "The Shire") + ("street" . "1234 Bag End, 98 Hobbiton") + ("gender" . "Male") + ("birthdate" . "1873-11-23") + ("parentlastname" . "Braggins") + ("parentfirstname" . "Bilbo") + ("lastname" . "Braggins") + ("firstname" . "Frodo")))) + (with-html-string + (:doctype) + (:html + (:head (:title "TFC Mission Trip Form") + (:style (apply #'lass:compile-and-write *mail-css*))) + (:body + (:h1 (format nil "Mission Trip Form for ~a ~a" "Chris" "Ccohrun")) + (:hr) + (:table + (loop for row in form + do (:tr + (:th (trim-whitespace (car row))) + (:td (trim-whitespace + (cdr row)))))))))) + :ssl :tls + :authentication '(:login "no-reply@mail.tfcconnection.org" "r9f36mNZFtiW4f") + ) (defun mail-form (form attachment) "Takes the form as an alist and sends a table formatted email @@ -450,65 +512,70 @@ with the image attached" ((eq request-type :post) (loop :for i :in parts :do (let* ((content-disposition - (nth 1 - (serapeum:lines i - :eol-style - :crlf - :honor-crlf t))) - (start (if content-disposition - (position #\" content-disposition))) - (end (if start - (position #\" content-disposition - :start (1+ start)) nil)) - (name (if end - (if start - (subseq content-disposition - (1+ start) end) nil) nil)) - (content - (if (string= name "image") - (butlast - (rest - (rest - (rest - (rest - (serapeum:lines i - :eol-style - :crlf - :honor-crlf t - :keep-eols t)))))) - (trim-whitespace - (car - (butlast - (rest - (rest - (rest - (serapeum:lines i :eol-style :crlf - :honor-crlf t - :keep-eols t))))))))) - (file-start - (if (string= name "image") - (position #\" content-disposition - :start 44))) - (file-end - (if file-start - (position #\" content-disposition - :start (1+ file-start)) nil)) - (image-file-name - (if (string= name "image") - (subseq content-disposition - (1+ file-start) file-end) nil))) + (nth 1 + (serapeum:lines i + :eol-style + :crlf + :honor-crlf t))) + (start (if content-disposition + (position #\" content-disposition))) + (end (if start + (position #\" content-disposition + :start (1+ start)) nil)) + (name (if end + (if start + (subseq content-disposition + (1+ start) end) nil) nil)) + (content + (if (string= name "image") + nil + ;; (butlast + ;; (rest + ;; (rest + ;; (rest + ;; (rest + ;; (serapeum:lines i + ;; :eol-style + ;; :crlf + ;; :honor-crlf t + ;; :keep-eols t)))))) + (trim-whitespace + (car + (butlast + (rest + (rest + (rest + (serapeum:lines i :eol-style :crlf + :honor-crlf t + :keep-eols t))))))))) + (file-start + (if (string= name "image") + (position #\" content-disposition + :start 44))) + (file-end + (if file-start + (position #\" content-disposition + :start (1+ file-start)) nil)) + (image-file-name + (if (string= name "image") + (subseq content-disposition + (1+ file-start) file-end) nil))) + (if name (if (string= name "image") - (if (uiop:file-exists-p image-file-name) - (progn - (save-string-file - (apply #'concatenate 'string content) - image-file-name) - (setq form-list (acons name image-file-name form-list)) - (setf attachment image-file-name))) + (when (stringp content) + (progn + (if (not (uiop:file-exists-p image-file-name)) + (save-string-file + (apply #'concatenate 'string content) + image-file-name)) + (setf attachment image-file-name) + (delete-file image-file-name))) (setq form-list (acons name content form-list)))))) (if (mail-mt-form form-list attachment) - (format nil "thankyou")))))) + (progn + (uiop:println "Mail sent") + (format nil "thankyou"))))))) (hunchentoot:define-easy-handler (respond :uri "/health-form") () (setf (hunchentoot:content-type*) "plain/text") diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5fa453d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,26 @@ +mod api; + +use actix_multipart::form::tempfile::TempFileConfig; +use actix_web::{middleware, App, HttpServer}; +use api::mt_form::mt_form; + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + + log::info!("creating temporary upload directory"); + std::fs::create_dir_all("./tmp")?; + + log::info!("starting HTTP server at http://localhost:4242"); + + HttpServer::new(|| { + App::new() + .wrap(middleware::Logger::default()) + .app_data(TempFileConfig::default().directory("./tmp")) + .service(mt_form) + }) + .bind(("127.0.0.1", 4242))? + .workers(2) + .run() + .await +}