From 403064ac6c5397c8a1c27d26e44fb0f32afbdd7b Mon Sep 17 00:00:00 2001 From: Franklin Date: Sat, 22 Apr 2023 20:45:15 -0400 Subject: [PATCH] Updates to backend, added uploading images with s3. --- Cargo.lock | 605 +++++++++++++++++- Cargo.toml | 4 + sql/agent/fetch_all.sql | 2 +- ...h_shortcode.sql => get_with_shortcode.sql} | 3 +- sqlx-data.json | 107 +++- src/dao/agent.rs | 9 + src/dao/contact.rs | 12 +- src/dao/mod.rs | 2 +- src/dao/project.rs | 9 +- src/dao/visit.rs | 18 +- src/main.rs | 13 + src/routes/admin.rs | 16 +- src/routes/main_router.rs | 53 +- src/routes/read.rs | 41 +- src/services/admin.rs | 12 +- src/services/read.rs | 36 +- src/utils/mod.rs | 3 +- src/utils/s3.rs | 53 ++ src/utils/visit.rs | 12 +- 19 files changed, 889 insertions(+), 121 deletions(-) rename sql/agent/{fetch_with_shortcode.sql => get_with_shortcode.sql} (73%) create mode 100644 src/utils/s3.rs diff --git a/Cargo.lock b/Cargo.lock index 200a54b..4fa6e12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" dependencies = [ "memchr", ] @@ -287,6 +287,367 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "aws-config" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd62464d1c4ad70f8b6cd693e7f30229f36bebdcdf3fce8c11803e1bdc0bc052" +dependencies = [ + "aws-credential-types", + "aws-http", + "aws-sdk-sso", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "hex", + "http", + "hyper", + "ring", + "time 0.3.20", + "tokio", + "tower", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-credential-types" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4232d3729eefc287adc0d5a8adc97b7d94eefffe6bbe94312cc86c7ab6b06ce" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "fastrand", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-endpoint" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f04ab03b3f1cca91f7cccaa213056d732accb14e2e65debfacc1d28627d162" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "aws-types", + "http", + "regex", + "tracing", +] + +[[package]] +name = "aws-http" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ad8c53f7560baaf635b6aa811f3213d39b50555d100f83e43801652d4e318e" +dependencies = [ + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-types", + "aws-types", + "bytes", + "http", + "http-body", + "lazy_static", + "percent-encoding", + "pin-project-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-s3" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b64fc8b7d76d09e53f4a64ebe2cd44894adb902011a26878aebd0576234d41" +dependencies = [ + "aws-credential-types", + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-client", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "http", + "http-body", + "once_cell", + "percent-encoding", + "regex", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "aws-sdk-sso" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143953d46f77a0b18480e7d8bb1a651080b9484e0bb94c27b8645eaeb3c3e231" +dependencies = [ + "aws-credential-types", + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-types", + "aws-types", + "bytes", + "http", + "regex", + "tokio-stream", + "tower", + "tracing", +] + +[[package]] +name = "aws-sdk-sts" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7255c0d8053b89e8b5cdabb52e1dbf596e9968b1f45dce7a56b2cd57038fcfc9" +dependencies = [ + "aws-credential-types", + "aws-endpoint", + "aws-http", + "aws-sig-auth", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-json", + "aws-smithy-query", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "http", + "regex", + "tower", + "tracing", +] + +[[package]] +name = "aws-sig-auth" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d77d879ab210e958ba65a6d3842969a596738c024989cd3e490cf9f9b560ec" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-types", + "http", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab4eebc8ec484fb9eab04b15a5d1e71f3dc13bee8fdd2d9ed78bcd6ecbd7192" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-http", + "bytes", + "form_urlencoded", + "hex", + "hmac", + "http", + "once_cell", + "percent-encoding", + "regex", + "sha2", + "time 0.3.20", + "tracing", +] + +[[package]] +name = "aws-smithy-async" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88573bcfbe1dcfd54d4912846df028b42d6255cbf9ce07be216b1bbfd11fc4b9" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", + "tokio-stream", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71a63d4f1c04b3abb7603001e4513f19617427bf27ca185b2ac663a1e342d39e" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc32c", + "crc32fast", + "hex", + "http", + "http-body", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-client" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f52352bae50d3337d5d6151b695d31a8c10ebea113eca5bead531f8301b067" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-tower", + "aws-smithy-types", + "bytes", + "fastrand", + "http", + "http-body", + "hyper", + "hyper-rustls", + "lazy_static", + "pin-project-lite", + "rustls", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168f08f8439c8b317b578a695e514c5cd7b869e73849a2d6b71ced4de6ce193d" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03bcc02d7ed9649d855c8ce4a735e9848d7b8f7568aad0504c158e3baa955df8" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http", + "http-body", + "hyper", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "aws-smithy-http-tower" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da88b3a860f65505996c29192d800f1aeb9480440f56d63aad33a3c12045017a" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "http", + "http-body", + "pin-project-lite", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b0c1e87d75cac889dca2a7f5ba280da2cde8122448e7fec1d614194dfa00c70" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-query" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b50d15f446c19e088009ecb00e2fb2d13133d6fe1db702e9aa67ad135bf6a6" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-types" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0afc731fd1417d791f9145a1e0c30e23ae0beaab9b4814017708ead2fc20f1" +dependencies = [ + "base64-simd", + "itoa", + "num-integer", + "ryu", + "time 0.3.20", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5398c1c25dfc6f8c282b1552a66aa807c9d6e15e1b3a84b94aa44e7859bec3" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b082e329d9a304d39e193ad5c7ab363a0d6507aca6965e0673a746686fb0cc" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-client", + "aws-smithy-http", + "aws-smithy-types", + "http", + "rustc_version", + "tracing", +] + [[package]] name = "base64" version = "0.13.1" @@ -299,6 +660,16 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + [[package]] name = "bincode" version = "1.3.3" @@ -346,9 +717,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" [[package]] name = "byteorder" @@ -362,6 +733,16 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bytes-utils" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47d3a8076e283f3acd27400535992edb3ba4b5bb72f8891ad8fbe7932a7d4b9" +dependencies = [ + "bytes", + "either", +] + [[package]] name = "bytestring" version = "1.3.0" @@ -451,6 +832,16 @@ dependencies = [ "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]] name = "core-foundation-sys" version = "0.8.4" @@ -459,9 +850,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" dependencies = [ "libc", ] @@ -481,6 +872,15 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +[[package]] +name = "crc32c" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfea2db42e9927a3845fb268a10a72faed6d416065f77873f05e411457c363e" +dependencies = [ + "rustc_version", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -663,6 +1063,15 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "flate2" version = "1.0.25" @@ -781,9 +1190,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" dependencies = [ "bytes", "fnv", @@ -924,7 +1333,9 @@ checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" dependencies = [ "http", "hyper", + "log", "rustls", + "rustls-native-certs", "tokio", "tokio-rustls", ] @@ -1010,6 +1421,8 @@ dependencies = [ "actix-cors", "actix-web", "actix-web-utils", + "aws-config", + "aws-sdk-s3", "chrono", "chrono-tz", "dotenv", @@ -1017,6 +1430,7 @@ dependencies = [ "dotenvy_macro", "err", "jl-types", + "rand", "reqwest", "serde", "serde_json", @@ -1065,10 +1479,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] -name = "libc" -version = "0.2.141" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "link-cplusplus" @@ -1162,7 +1582,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1210,6 +1630,18 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + [[package]] name = "parking_lot" version = "0.11.2" @@ -1255,7 +1687,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1317,6 +1749,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1411,9 +1863,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" dependencies = [ "aho-corasick", "memchr", @@ -1422,9 +1874,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" [[package]] name = "reqwest" @@ -1501,6 +1953,18 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls-native-certs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "1.0.2" @@ -1516,6 +1980,15 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1538,6 +2011,29 @@ dependencies = [ "untrusted", ] +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.17" @@ -1900,7 +2396,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.45.0", ] [[package]] @@ -1950,6 +2446,28 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -1965,9 +2483,21 @@ dependencies = [ "cfg-if", "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -2045,6 +2575,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "urlencoding" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" + [[package]] name = "uuid" version = "1.3.1" @@ -2074,6 +2610,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "want" version = "0.3.0" @@ -2241,6 +2783,21 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -2373,6 +2930,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "xmlparser" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" + [[package]] name = "zstd" version = "0.12.3+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 5fdcba0..c66e051 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,8 @@ uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics"] } actix-web-utils = { git = "https://git.franklinblanco.dev/franklinblanco/actix-web-utils.git" } err = { git = "https://git.franklinblanco.dev/franklinblanco/err.git" } +aws-config = "0.55.1" +aws-sdk-s3 = "0.26.0" +rand = "0.8.5" + jl-types = { path = "../jl-types", features = ["sqlx"]} \ No newline at end of file diff --git a/sql/agent/fetch_all.sql b/sql/agent/fetch_all.sql index b61f06f..af1b964 100644 --- a/sql/agent/fetch_all.sql +++ b/sql/agent/fetch_all.sql @@ -8,4 +8,4 @@ SELECT time_created, last_updated FROM agent -ORDER BY full_name DESC; \ No newline at end of file +ORDER BY full_name ASC; \ No newline at end of file diff --git a/sql/agent/fetch_with_shortcode.sql b/sql/agent/get_with_shortcode.sql similarity index 73% rename from sql/agent/fetch_with_shortcode.sql rename to sql/agent/get_with_shortcode.sql index 7a5e7fa..f020705 100644 --- a/sql/agent/fetch_with_shortcode.sql +++ b/sql/agent/get_with_shortcode.sql @@ -7,5 +7,4 @@ SELECT profile_picture_url, time_created, last_updated -FROM agent where shortcode = $1 -ORDER BY time_created DESC; \ No newline at end of file +FROM agent where shortcode = $1; \ No newline at end of file diff --git a/sqlx-data.json b/sqlx-data.json index 1650d3a..6d27d63 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -12,7 +12,7 @@ }, "query": "DELETE FROM agent WHERE id = $1;" }, - "181ffb1869d9acb225071b9a5650510f29fca447892f698ae597d370764e35ad": { + "11b388533d1cece58959754172768a0fa4bfd430ad29a3bf0eca81bbbe7ecc22": { "describe": { "columns": [ { @@ -79,11 +79,12 @@ "Text", "Text", "Text", + "Int2", "Int8" ] } }, - "query": "SELECT \n p.id,\n p.project_state as \"project_state: _\",\n p.project_type as \"project_type: _\",\n p.project_condition as \"project_condition: _\",\n l.city,\n (SELECT (SELECT u.price_usd FROM unit u WHERE u.project_id = p.id ORDER BY u.price_usd DESC LIMIT 1)) as starts_from,\n l.district,\n p.finish_date,\n p.media as \"media: _\"\nFROM project p, location l\nWHERE p.location_id = l.id\n-- Filters here:\nAND (LOWER(l.city) LIKE '%' || LOWER($1) || '%' OR $1 IS null) -- City Filter\nAND (LOWER(l.district) LIKE '%' || LOWER($2) || '%' OR $2 IS null) -- District Filter\nAND (p.project_type = $3 OR $3 IS null) -- ProjectType\nAND (p.project_condition = $4 OR $4 IS null) -- ProjectCondition\nAND (p.project_state = $5 OR $5 IS null) -- ProjectState\n-- End of filters\nORDER BY p.time_created DESC\nLIMIT 50 OFFSET $6;" + "query": "SELECT \n p.id,\n p.project_state as \"project_state: _\",\n p.project_type as \"project_type: _\",\n p.project_condition as \"project_condition: _\",\n l.city,\n (SELECT (SELECT u.price_usd FROM unit u WHERE u.project_id = p.id ORDER BY u.price_usd DESC LIMIT 1)) as starts_from,\n l.district,\n p.finish_date,\n p.media as \"media: _\"\nFROM project p, location l\nWHERE p.location_id = l.id\n-- Filters here:\nAND (LOWER(l.city) LIKE '%' || LOWER($1) || '%' OR $1 IS null) -- City Filter\nAND (LOWER(l.district) LIKE '%' || LOWER($2) || '%' OR $2 IS null) -- District Filter\nAND (p.project_type = $3 OR $3 IS null) -- ProjectType\nAND (p.project_condition = $4 OR $4 IS null) -- ProjectCondition\nAND (p.project_state = $5 OR $5 IS null) -- ProjectState\nAND ((SELECT COUNT(*) FROM unit u WHERE u.project_id = p.id AND u.rooms = $6) > 0 OR $6 IS NULL)\n-- End of filters\nORDER BY p.time_created DESC\nLIMIT 50 OFFSET $7;" }, "19a20556f5e3621438cd583aae4984c8cf510f359f65ec599f8a6b46d9153ec4": { "describe": { @@ -217,6 +218,68 @@ }, "query": "DELETE FROM location where id = $1;" }, + "44a6ca26f099484f650c58858cc54aae7e1210b9618ad6b123f22e02db729381": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Uuid" + }, + { + "name": "shortcode", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "full_name", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "credential", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "credential_type: _", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "profile_picture_url", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "time_created", + "ordinal": 6, + "type_info": "Timestamptz" + }, + { + "name": "last_updated", + "ordinal": 7, + "type_info": "Timestamptz" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "SELECT \n id,\n shortcode,\n full_name,\n credential,\n credential_type as \"credential_type: _\",\n profile_picture_url,\n time_created,\n last_updated\nFROM agent where shortcode = $1;" + }, "4ef2f2177dd00503913e281cf97bd922bcdc4b30ed834505eb8ea9a396f73331": { "describe": { "columns": [], @@ -303,25 +366,7 @@ }, "query": "DELETE FROM unit WHERE id = $1;" }, - "70fa05f0ac30cba1fb2c3c356d1da567a1b3b417bdfd313f1d3b55c550e217f0": { - "describe": { - "columns": [ - { - "name": "count", - "ordinal": 0, - "type_info": "Int8" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "SELECT COUNT(*) FROM visit;" - }, - "7792ad0bec652b57156e4ac7010324a97984263434702de060ceab7cdcf691c0": { + "58c56b5239d3756507a0dbedf40217a7e345c4a60b1042d0cbabf49dc80d1aa4": { "describe": { "columns": [ { @@ -379,7 +424,25 @@ "Left": [] } }, - "query": "SELECT\n id,\n shortcode,\n full_name,\n credential,\n credential_type as \"credential_type: _\",\n profile_picture_url,\n time_created,\n last_updated\nFROM agent\nORDER BY full_name DESC;" + "query": "SELECT\n id,\n shortcode,\n full_name,\n credential,\n credential_type as \"credential_type: _\",\n profile_picture_url,\n time_created,\n last_updated\nFROM agent\nORDER BY full_name ASC;" + }, + "70fa05f0ac30cba1fb2c3c356d1da567a1b3b417bdfd313f1d3b55c550e217f0": { + "describe": { + "columns": [ + { + "name": "count", + "ordinal": 0, + "type_info": "Int8" + } + ], + "nullable": [ + null + ], + "parameters": { + "Left": [] + } + }, + "query": "SELECT COUNT(*) FROM visit;" }, "825e1ac484241349c54e75bb77186ce41ea98fd17cabd7308e737a6c9c5812a9": { "describe": { diff --git a/src/dao/agent.rs b/src/dao/agent.rs index 4211a09..b6da266 100644 --- a/src/dao/agent.rs +++ b/src/dao/agent.rs @@ -30,6 +30,15 @@ pub async fn get_agent_with_id( .await } +pub async fn get_agent_with_shortcode( + conn: &PgPool, + shortcode: &String, +) -> Result, sqlx::Error> { + sqlx::query_file_as!(Agent, "sql/agent/get_with_shortcode.sql", shortcode) + .fetch_optional(conn) + .await +} + pub async fn get_agents_with_ids( conn: &PgPool, agent_ids: &Vec, diff --git a/src/dao/contact.rs b/src/dao/contact.rs index 5cc7c12..87a631a 100644 --- a/src/dao/contact.rs +++ b/src/dao/contact.rs @@ -1,4 +1,4 @@ -use jl_types::domain::{count::Count, contact::Contact}; +use jl_types::domain::{contact::Contact, count::Count}; use sqlx::{postgres::PgQueryResult, PgPool}; pub async fn insert(db_conn: &PgPool, contact: &Contact) -> Result { @@ -15,9 +15,13 @@ pub async fn insert(db_conn: &PgPool, contact: &Contact) -> Result Result, sqlx::Error> { - sqlx::query_file_as!(Contact, "sql/contact/get_all.sql").fetch_all(db_conn).await + sqlx::query_file_as!(Contact, "sql/contact/get_all.sql") + .fetch_all(db_conn) + .await } pub async fn get_count(db_conn: &PgPool) -> Result { - sqlx::query_file_as!(Count, "sql/contact/get_count.sql").fetch_one(db_conn).await -} \ No newline at end of file + sqlx::query_file_as!(Count, "sql/contact/get_count.sql") + .fetch_one(db_conn) + .await +} diff --git a/src/dao/mod.rs b/src/dao/mod.rs index a9f352b..7353265 100644 --- a/src/dao/mod.rs +++ b/src/dao/mod.rs @@ -1,7 +1,7 @@ pub mod agent; +pub mod contact; pub mod location; pub mod main_dao; pub mod project; pub mod unit; pub mod visit; -pub mod contact; \ No newline at end of file diff --git a/src/dao/project.rs b/src/dao/project.rs index 4b89eea..4b05218 100644 --- a/src/dao/project.rs +++ b/src/dao/project.rs @@ -88,7 +88,7 @@ pub async fn fetch_with_filters_paged( let mut city_filter = None; let mut district_filter = None; let mut project_type_filter = None; - let mut project_state_filter = ProjectState::InConstruction; + let mut project_state_filter = None; let mut project_condition_filter = None; let mut project_room_count_filter = None; @@ -96,14 +96,13 @@ pub async fn fetch_with_filters_paged( match filter { Filter::InCity(city) => city_filter = Some(city), Filter::InDistrict(district) => district_filter = Some(district), - Filter::Finished => project_state_filter = ProjectState::Finished, + Filter::Finished => project_state_filter = Some(ProjectState::Finished), + Filter::InConstruction => project_state_filter = Some(ProjectState::InConstruction), Filter::ByProjectType(project_type) => project_type_filter = Some(project_type), Filter::ByProjectCondition(project_condition) => { project_condition_filter = Some(project_condition) } - Filter::ByRoomCount(room_count) => { - project_room_count_filter = Some(room_count) - }, + Filter::ByRoomCount(room_count) => project_room_count_filter = Some(room_count), } } diff --git a/src/dao/visit.rs b/src/dao/visit.rs index 0fcef42..e289c31 100644 --- a/src/dao/visit.rs +++ b/src/dao/visit.rs @@ -1,16 +1,14 @@ -use jl_types::domain::{visit::Visit, count::Count}; +use jl_types::domain::{count::Count, visit::Visit}; use sqlx::{postgres::PgQueryResult, PgPool}; pub async fn insert(db_conn: &PgPool, visit: &Visit) -> Result { - sqlx::query_file!( - "sql/visit/insert.sql", - visit.ip_addr, - visit.time_created, - ) - .execute(db_conn) - .await + sqlx::query_file!("sql/visit/insert.sql", visit.ip_addr, visit.time_created,) + .execute(db_conn) + .await } pub async fn get_count(db_conn: &PgPool) -> Result { - sqlx::query_file_as!(Count, "sql/visit/get_count.sql").fetch_one(db_conn).await -} \ No newline at end of file + sqlx::query_file_as!(Count, "sql/visit/get_count.sql") + .fetch_one(db_conn) + .await +} diff --git a/src/main.rs b/src/main.rs index 39e3efc..98374fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,3 +19,16 @@ async fn main() { .await .unwrap(); } + +#[cfg(test)] +mod tests { + /*use crate::utils::s3; + + #[tokio::test] + async fn test_aws_s3_put_object() { + let client = s3::init_aws_client().await; + let result = s3::upload_image(&client).await; + println!("{:?}", result); + assert!(result.is_ok()); + }*/ +} diff --git a/src/routes/admin.rs b/src/routes/admin.rs index 2efd841..783de95 100644 --- a/src/routes/admin.rs +++ b/src/routes/admin.rs @@ -1,12 +1,15 @@ use std::sync::Arc; use actix_web::{ - delete, post, put, - web::{self, Path}, get, + delete, get, post, put, + web::{self, Path}, }; use actix_web_utils::extensions::typed_response::TypedHttpResponse; use jl_types::{ - domain::{agent::Agent, location::Location, project::Project, unit::Unit, count::Count, contact::Contact}, + domain::{ + agent::Agent, contact::Contact, count::Count, location::Location, project::Project, + unit::Unit, + }, dto::payloads::{ agent::{NewAgentPayload, UpdateAgentPayload}, location::NewLocationPayload, @@ -17,7 +20,7 @@ use jl_types::{ use sqlx::PgPool; use uuid::Uuid; -use crate::services; +use crate::{services, utils::s3::Item}; #[post("/agent")] pub async fn create_new_agent_profile( @@ -122,4 +125,7 @@ pub async fn get_all_contacts(db_conn: web::Data>) -> TypedHttpRespo services::admin::get_all_contacts(&db_conn).await } - +#[post("images/{item}/{id}/{file_name}")] +pub async fn upload_image(aws_client: web::Data>, path_vars: Path<(Item, Uuid, String)>) -> TypedHttpResponse { + services::admin::upload_image(&aws_client, path_vars.0.clone(), path_vars.1, path_vars.2.clone()).await +} \ No newline at end of file diff --git a/src/routes/main_router.rs b/src/routes/main_router.rs index 5e4616a..3c9b24e 100644 --- a/src/routes/main_router.rs +++ b/src/routes/main_router.rs @@ -1,16 +1,19 @@ use std::sync::Arc; use actix_cors::Cors; -use actix_web::{web, App, HttpServer}; +use actix_web::{web::{self}, App, HttpServer}; use chrono::Utc; use reqwest::Client; use sqlx::PgPool; +use crate::utils::s3; + pub const HOST_ADDR: &str = "0.0.0.0"; pub const HOST_PORT: u16 = 8095; pub async fn start_all_routes(start_time: i64, db_conn: Arc) -> Result<(), std::io::Error> { let client_state = web::Data::new(Arc::new(Client::new())); + let aws_client = web::Data::new(Arc::new(s3::init_aws_client().await)); // Start server code that turns into a future to be executed below let server_future = HttpServer::new(move || { let cors_policy = Cors::permissive(); @@ -18,29 +21,35 @@ pub async fn start_all_routes(start_time: i64, db_conn: Arc) -> Result<( .wrap(cors_policy) .app_data(client_state.clone()) .app_data(web::Data::new(db_conn.clone())) + .app_data(aws_client.clone()) .service( web::scope("/admin") - .service(super::admin::create_new_agent_profile) - .service(super::admin::create_new_location) - .service(super::admin::create_new_project) - .service(super::admin::create_new_unit) - .service(super::admin::update_agent) - .service(super::admin::update_project) - .service(super::admin::update_unit) - .service(super::admin::delete_agent) - .service(super::admin::delete_location) - .service(super::admin::delete_project) - .service(super::admin::delete_unit) - .service(super::admin::get_all_contacts) - .service(super::admin::get_contacts_count) - .service(super::admin::get_visits_count)) - .service(web::scope("/read") - .service(super::read::get_all_agents) - .service(super::read::get_all_locations) - .service(super::read::get_locations_in_city) - .service(super::read::get_projects_paged) - .service(super::read::get_project_data) - .service(super::read::create_contact_request)) + .service(super::admin::create_new_agent_profile) + .service(super::admin::create_new_location) + .service(super::admin::create_new_project) + .service(super::admin::create_new_unit) + .service(super::admin::update_agent) + .service(super::admin::update_project) + .service(super::admin::update_unit) + .service(super::admin::delete_agent) + .service(super::admin::delete_location) + .service(super::admin::delete_project) + .service(super::admin::delete_unit) + .service(super::admin::get_all_contacts) + .service(super::admin::get_contacts_count) + .service(super::admin::get_visits_count) + .service(super::admin::upload_image) + ) + .service( + web::scope("/read") + .service(super::read::get_all_agents) + .service(super::read::get_all_locations) + .service(super::read::get_locations_in_city) + .service(super::read::get_projects_paged) + .service(super::read::get_project_data) + .service(super::read::create_contact_request) + .service(super::read::get_agent_with_shortcode), + ) }) .bind((HOST_ADDR, HOST_PORT))? .run(); diff --git a/src/routes/read.rs b/src/routes/read.rs index 15a5ff6..9bff50f 100644 --- a/src/routes/read.rs +++ b/src/routes/read.rs @@ -1,17 +1,22 @@ -use std::{collections::{HashMap, HashSet}, str::FromStr, sync::Arc}; +use std::{ + collections::{HashMap, HashSet}, + str::FromStr, + sync::Arc, +}; use actix_web::{ - get, - web::{self, Path}, HttpRequest, post, + get, post, + web::{self, Path}, + HttpRequest, }; use actix_web_utils::extensions::typed_response::TypedHttpResponse; use err::MessageResource; use jl_types::{ - domain::{ - agent::Agent, project_condition::ProjectCondition, - project_type::ProjectType, + domain::{agent::Agent, project_condition::ProjectCondition, project_type::ProjectType}, + dto::{ + filters::Filter, listing::Listing, payloads::contact::ContactPayload, + project_card::ProjectCardDto, }, - dto::{filters::Filter, listing::Listing, project_card::ProjectCardDto, payloads::contact::ContactPayload}, }; use sqlx::PgPool; use uuid::Uuid; @@ -23,6 +28,14 @@ pub async fn get_all_agents(db_conn: web::Data>) -> TypedHttpRespons services::read::get_all_agents(&db_conn).await } +#[get("/agent/{shortcode}")] +pub async fn get_agent_with_shortcode( + db_conn: web::Data>, + shortcode: web::Path, +) -> TypedHttpResponse { + services::read::get_agent_with_shortcode(&db_conn, &shortcode).await +} + #[get("/locations")] pub async fn get_all_locations( db_conn: web::Data>, @@ -62,7 +75,10 @@ pub async fn get_project_data( } #[post("/contact")] -pub async fn create_contact_request(db_conn: web::Data>, contact: web::Json) -> TypedHttpResponse<()> { +pub async fn create_contact_request( + db_conn: web::Data>, + contact: web::Json, +) -> TypedHttpResponse<()> { services::read::create_contact(&db_conn, contact.0).await } @@ -80,9 +96,8 @@ fn parse_params_into_filters( let district = params.get(key).unwrap(); filters.push(Filter::InDistrict(district.clone())); } - "finished" => { - filters.push(Filter::Finished); - } + "finished" => filters.push(Filter::Finished), + "inconstruction" => filters.push(Filter::InConstruction), "byprojecttype" => { let project_type = params.get(key).unwrap(); match ProjectType::from_str(project_type) { @@ -101,9 +116,9 @@ fn parse_params_into_filters( let room_count = params.get(key).unwrap(); match i32::from_str(&room_count) { Ok(room_count) => filters.push(Filter::ByRoomCount(room_count)), - Err(_) => {}, + Err(_) => {} } - }, + } _ => {} }; } diff --git a/src/services/admin.rs b/src/services/admin.rs index 64d5bee..1262fac 100644 --- a/src/services/admin.rs +++ b/src/services/admin.rs @@ -1,6 +1,9 @@ use actix_web_utils::extensions::typed_response::TypedHttpResponse; use jl_types::{ - domain::{agent::Agent, location::Location, project::Project, unit::Unit, count::Count, contact::Contact}, + domain::{ + agent::Agent, contact::Contact, count::Count, location::Location, project::Project, + unit::Unit, + }, dto::payloads::{ agent::{NewAgentPayload, UpdateAgentPayload}, location::NewLocationPayload, @@ -12,7 +15,7 @@ use jl_types::{ use sqlx::PgPool; use uuid::Uuid; -use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found}; +use crate::{dao, handle_db_read_op, handle_db_write_op, handle_tx, success, unwrap_or_not_found, utils::s3::{Item}}; // // Insert Methods @@ -191,4 +194,9 @@ pub async fn get_all_contacts(conn: &PgPool) -> TypedHttpResponse> pub async fn get_contact_count(conn: &PgPool) -> TypedHttpResponse { let count = handle_db_read_op!(dao::contact::get_count(conn)); success!(count) +} + +pub async fn upload_image(_client: &aws_sdk_s3::Client, _item: Item, _id: Uuid, _file_name: String) -> TypedHttpResponse { + + success!(String::new()) } \ No newline at end of file diff --git a/src/services/read.rs b/src/services/read.rs index d3ced30..404a116 100644 --- a/src/services/read.rs +++ b/src/services/read.rs @@ -2,8 +2,11 @@ use std::collections::HashSet; use actix_web_utils::extensions::typed_response::TypedHttpResponse; use jl_types::{ - domain::{agent::Agent}, - dto::{filters::Filter, listing::Listing, project_card::ProjectCardDto, payloads::contact::ContactPayload}, + domain::agent::Agent, + dto::{ + filters::Filter, listing::Listing, payloads::contact::ContactPayload, + project_card::ProjectCardDto, + }, }; use sqlx::PgPool; use uuid::Uuid; @@ -14,10 +17,22 @@ pub async fn get_all_agents(conn: &PgPool) -> TypedHttpResponse> { success!(handle_db_read_op!(dao::agent::fetch_all(conn))) } +pub async fn get_agent_with_shortcode( + conn: &PgPool, + shortcode: &String, +) -> TypedHttpResponse { + success!(unwrap_or_not_found!( + handle_db_read_op!(dao::agent::get_agent_with_shortcode(conn, shortcode)), + "agents" + )) +} + pub async fn get_all_locations(conn: &PgPool) -> TypedHttpResponse> { - let locations: HashSet = handle_db_read_op!(dao::location::fetch_all_locations(conn)).into_iter().map(|location| location.city).collect(); - - + let locations: HashSet = handle_db_read_op!(dao::location::fetch_all_locations(conn)) + .into_iter() + .map(|location| location.city) + .collect(); + success!(locations) } @@ -25,9 +40,12 @@ pub async fn get_all_locations_in_city( conn: &PgPool, city: &String, ) -> TypedHttpResponse> { - success!(handle_db_read_op!(dao::location::get_locations_in_city( - conn, city - )).into_iter().map(|location| location.district).collect()) + success!( + handle_db_read_op!(dao::location::get_locations_in_city(conn, city)) + .into_iter() + .map(|location| location.district) + .collect() + ) } pub async fn get_projects_paged( @@ -64,4 +82,4 @@ pub async fn get_project_data(conn: &PgPool, project_id: &Uuid) -> TypedHttpResp pub async fn create_contact(conn: &PgPool, contact: ContactPayload) -> TypedHttpResponse<()> { let _ = handle_db_read_op!(dao::contact::insert(conn, &contact.into())); success!(()) -} \ No newline at end of file +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d1af5ac..8e69244 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,2 +1,3 @@ pub mod macros; -pub mod visit; \ No newline at end of file +pub mod s3; +pub mod visit; diff --git a/src/utils/s3.rs b/src/utils/s3.rs new file mode 100644 index 0000000..ac2f7c6 --- /dev/null +++ b/src/utils/s3.rs @@ -0,0 +1,53 @@ +use std::fmt::Display; + +use aws_sdk_s3::{ + error::SdkError, + operation::put_object::{PutObjectError}, + primitives::ByteStream, + Client, +}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] +pub enum Item { + #[default] + Project, + Unit, + Agent, +} +impl Display for Item { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Item::Project => write!(f, "Project"), + Item::Unit => write!(f, "Unit"), + Item::Agent => write!(f, "Agent"), + } + } +} + +pub async fn init_aws_client() -> Client { + dotenv::dotenv().expect("Failed loading env"); + let config = aws_config::load_from_env().await; + Client::new(&config) +} + +pub async fn upload_image( + client: &Client, + id: Uuid, + item: Item, + file_name: String, +) -> Result> { + let path = format!("jl-images/{item}/{id}/{file_name}"); + match client + .put_object() + .bucket("jorge-ledesma-bucket") + .key(path.clone()) + .body(ByteStream::from_static("Hey there".as_bytes())) + .acl(aws_sdk_s3::types::ObjectCannedAcl::PublicRead) + .send() + .await { + Ok(_) => Ok(format!("https://jorge-ledesma-bucket.s3.us-east-2.amazonaws.com/{path}")), + Err(error) => Err(error), + } +} diff --git a/src/utils/visit.rs b/src/utils/visit.rs index ebe33ee..34bdd55 100644 --- a/src/utils/visit.rs +++ b/src/utils/visit.rs @@ -6,15 +6,15 @@ use sqlx::PgPool; use crate::dao; - pub fn store_visit_concurrent(db_conn: &Arc, request: HttpRequest) { let ip = request.peer_addr().unwrap(); let db_conn = db_conn.clone(); tokio::spawn(async move { match dao::visit::insert(&db_conn, &Visit::new(ip.to_string())).await { - Ok(_) => {}, - Err(error) => { println!("{}", error) }, - }; + Ok(_) => {} + Err(error) => { + println!("{}", error) + } + }; }); - -} \ No newline at end of file +}