Merge branch '6-feat-add-the-ability-to-rollback-last-tweet' into 'main'

feat: add the ability to rollback last tweet

Closes #6

See merge request veretcle/oolatoocs!12
This commit is contained in:
VC
2024-01-09 13:04:01 +00:00
7 changed files with 635 additions and 158 deletions

367
Cargo.lock generated
View File

@@ -19,13 +19,14 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.7.7"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd"
checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01"
dependencies = [
"getrandom",
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
]
[[package]]
@@ -37,6 +38,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "allocator-api2"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -102,13 +109,13 @@ dependencies = [
[[package]]
name = "async-trait"
version = "0.1.75"
version = "0.1.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98"
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
@@ -140,9 +147,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.5"
version = "0.21.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9"
[[package]]
name = "bitflags"
@@ -215,18 +222,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.11"
version = "4.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2"
checksum = "33e92c5c1a78c62968ec57dbc2440366a2d6e5a23faf829970ff1585dc6b18e2"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.4.11"
version = "4.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb"
checksum = "f4323769dc8a61e2c39ad7dc26f6f2800524691a44d74fe3d1071a5c24db6370"
dependencies = [
"anstream",
"anstyle",
@@ -264,9 +271,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "cpufeatures"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
dependencies = [
"libc",
]
@@ -338,9 +345,9 @@ dependencies = [
[[package]]
name = "fallible-iterator"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
[[package]]
name = "fallible-streaming-iterator"
@@ -392,9 +399,9 @@ dependencies = [
[[package]]
name = "futures"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
@@ -407,9 +414,9 @@ dependencies = [
[[package]]
name = "futures-channel"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [
"futures-core",
"futures-sink",
@@ -417,15 +424,15 @@ dependencies = [
[[package]]
name = "futures-core"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
@@ -434,38 +441,38 @@ dependencies = [
[[package]]
name = "futures-io"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
[[package]]
name = "futures-macro"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
name = "futures-sink"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
[[package]]
name = "futures-task"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.29"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-channel",
"futures-core",
@@ -491,9 +498,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"js-sys",
@@ -519,7 +526,7 @@ dependencies = [
"futures-core",
"futures-sink",
"futures-util",
"http",
"http 0.2.11",
"indexmap",
"slab",
"tokio",
@@ -527,28 +534,23 @@ dependencies = [
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
dependencies = [
"ahash",
"allocator-api2",
]
[[package]]
name = "hashlink"
version = "0.7.0"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
dependencies = [
"hashbrown 0.11.2",
"hashbrown",
]
[[package]]
@@ -592,6 +594,17 @@ dependencies = [
"itoa",
]
[[package]]
name = "http"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.6"
@@ -599,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http",
"http 0.2.11",
"pin-project-lite",
]
@@ -632,7 +645,7 @@ dependencies = [
"futures-core",
"futures-util",
"h2",
"http",
"http 0.2.11",
"http-body",
"httparse",
"httpdate",
@@ -652,11 +665,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [
"futures-util",
"http",
"http 0.2.11",
"hyper",
"rustls",
"rustls 0.21.10",
"tokio",
"tokio-rustls",
"tokio-rustls 0.24.1",
]
[[package]]
@@ -674,9 +687,9 @@ dependencies = [
[[package]]
name = "iana-time-zone"
version = "0.1.58"
version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
dependencies = [
"android_system_properties",
"core-foundation-sys",
@@ -712,7 +725,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
"hashbrown",
]
[[package]]
@@ -723,13 +736,13 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
version = "0.4.9"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
dependencies = [
"hermit-abi",
"rustix",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -755,15 +768,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "libsqlite3-sys"
version = "0.24.2"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
dependencies = [
"pkg-config",
"vcpkg",
@@ -793,15 +806,14 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "megalodon"
version = "0.11.7"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b9ee1d70f03dc0a197e6966320449e6ed55d14f74b0ea64ae1dffce9ce6d236"
checksum = "dc8942e3eaac5e7d0601819dbff08a751377ca5a9e6389436da7a16046dbbcb4"
dependencies = [
"async-trait",
"chrono",
"futures-util",
"hex",
"http",
"log",
"oauth2",
"rand",
@@ -821,9 +833,9 @@ dependencies = [
[[package]]
name = "memchr"
version = "2.6.4"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
[[package]]
name = "mime"
@@ -944,7 +956,7 @@ dependencies = [
"base64 0.13.1",
"chrono",
"getrandom",
"http",
"http 0.2.11",
"rand",
"reqwest",
"serde",
@@ -957,9 +969,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.32.1"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"memchr",
]
@@ -972,7 +984,7 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "oolatoocs"
version = "1.5.4"
version = "2.0.0"
dependencies = [
"chrono",
"clap",
@@ -992,9 +1004,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.61"
version = "0.10.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45"
checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671"
dependencies = [
"bitflags 2.4.1",
"cfg-if",
@@ -1013,7 +1025,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
@@ -1024,9 +1036,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.97"
version = "0.9.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b"
checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7"
dependencies = [
"cc",
"libc",
@@ -1123,18 +1135,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.71"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@@ -1213,13 +1225,13 @@ version = "0.11.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41"
dependencies = [
"base64 0.21.5",
"base64 0.21.6",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http 0.2.11",
"http-body",
"hyper",
"hyper-rustls",
@@ -1233,15 +1245,15 @@ dependencies = [
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls",
"rustls-pemfile",
"rustls 0.21.10",
"rustls-pemfile 1.0.4",
"serde",
"serde_json",
"serde_urlencoded",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-rustls",
"tokio-rustls 0.24.1",
"tokio-util",
"tower-service",
"url",
@@ -1269,16 +1281,16 @@ dependencies = [
[[package]]
name = "rusqlite"
version = "0.27.0"
version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a"
checksum = "a78046161564f5e7cd9008aff3b2990b3850dc8e0349119b98e8f251e099f24d"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.4.1",
"chrono",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
]
@@ -1309,18 +1321,33 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
dependencies = [
"log",
"ring",
"rustls-webpki",
"rustls-webpki 0.101.7",
"sct",
]
[[package]]
name = "rustls-native-certs"
version = "0.6.3"
name = "rustls"
version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41"
dependencies = [
"log",
"ring",
"rustls-pki-types",
"rustls-webpki 0.102.1",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792"
dependencies = [
"openssl-probe",
"rustls-pemfile",
"rustls-pemfile 2.0.0",
"rustls-pki-types",
"schannel",
"security-framework",
]
@@ -1331,9 +1358,25 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
dependencies = [
"base64 0.21.5",
"base64 0.21.6",
]
[[package]]
name = "rustls-pemfile"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
dependencies = [
"base64 0.21.6",
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a"
[[package]]
name = "rustls-webpki"
version = "0.101.7"
@@ -1344,6 +1387,17 @@ dependencies = [
"untrusted",
]
[[package]]
name = "rustls-webpki"
version = "0.102.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b"
dependencies = [
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "ryu"
version = "1.0.16"
@@ -1352,11 +1406,11 @@ checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "schannel"
version = "0.1.22"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
dependencies = [
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -1400,29 +1454,29 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.193"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.193"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
name = "serde_json"
version = "1.0.108"
version = "1.0.111"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4"
dependencies = [
"itoa",
"ryu",
@@ -1431,9 +1485,9 @@ dependencies = [
[[package]]
name = "serde_path_to_error"
version = "0.1.14"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335"
checksum = "ebd154a240de39fdebcf5775d2675c204d7c13cf39a4c697be6493c8e734337c"
dependencies = [
"itoa",
"serde",
@@ -1558,9 +1612,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.42"
version = "2.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
dependencies = [
"proc-macro2",
"quote",
@@ -1590,15 +1644,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.8.1"
version = "3.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@@ -1612,22 +1666,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.51"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.51"
version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
@@ -1672,7 +1726,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
]
[[package]]
@@ -1691,22 +1745,34 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [
"rustls",
"rustls 0.21.10",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f"
dependencies = [
"rustls 0.22.2",
"rustls-pki-types",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.20.1"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38"
dependencies = [
"futures-util",
"log",
"rustls",
"rustls 0.22.2",
"rustls-native-certs",
"rustls-pki-types",
"tokio",
"tokio-rustls",
"tokio-rustls 0.25.0",
"tungstenite",
]
@@ -1802,18 +1868,19 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
version = "0.20.1"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9"
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1"
dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http",
"http 1.0.0",
"httparse",
"log",
"rand",
"rustls",
"rustls 0.22.2",
"rustls-pki-types",
"sha1",
"thiserror",
"url",
@@ -1955,7 +2022,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
"wasm-bindgen-shared",
]
@@ -1989,7 +2056,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.42",
"syn 2.0.48",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2062,11 +2129,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.51.1"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.48.5",
"windows-targets 0.52.0",
]
[[package]]
@@ -2203,9 +2270,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.30"
version = "0.5.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5"
checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa"
dependencies = [
"memchr",
]
@@ -2219,3 +2286,29 @@ dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[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.48",
]
[[package]]
name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"

View File

@@ -1,6 +1,6 @@
[package]
name = "oolatoocs"
version = "1.5.4"
version = "2.0.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -16,7 +16,7 @@ megalodon = "^0.11"
oauth1-request = "^0.6"
regex = "^1.10"
reqwest = { version = "^0.11", features = ["json", "stream", "multipart"] }
rusqlite = "^0.27"
rusqlite = { version = "^0.30", features = ["chrono"] }
serde = { version = "^1.0", features = ["derive"] }
tokio = { version = "^1.33", features = ["rt-multi-thread", "macros", "time"] }
toml = "^0.8"

View File

@@ -5,20 +5,20 @@ mod config;
pub use config::{parse_toml, Config};
mod state;
pub use state::init_db;
#[allow(unused_imports)]
use state::{read_state, write_state, TweetToToot};
use state::{delete_state, read_all_tweet_state, read_state, write_state, TweetToToot};
pub use state::{init_db, migrate_db};
mod mastodon;
use mastodon::get_mastodon_timeline_since;
pub use mastodon::register;
use mastodon::{get_mastodon_instance, get_mastodon_timeline_since, get_status_edited_at};
mod utils;
use utils::{generate_multi_tweets, strip_everything};
mod twitter;
#[allow(unused_imports)]
use twitter::{generate_media_ids, post_tweet, transform_poll};
use twitter::{delete_tweet, generate_media_ids, post_tweet, transform_poll};
use rusqlite::Connection;
@@ -27,11 +27,51 @@ pub async fn run(config: &Config) {
let conn = Connection::open(&config.oolatoocs.db_path)
.unwrap_or_else(|e| panic!("Cannot open DB: {}", e));
let last_toot_id = read_state(&conn, None)
.unwrap_or_else(|e| panic!("Cannot get last toot id: {}", e))
.map(|r| r.toot_id);
let mastodon = get_mastodon_instance(&config.mastodon);
let timeline = get_mastodon_timeline_since(&config.mastodon, last_toot_id)
let last_entry =
read_state(&conn, None).unwrap_or_else(|e| panic!("Cannot get last toot id: {}", e));
let last_toot_id: Option<u64> = match last_entry {
None => None, // Does not exist, this is the same as previously
Some(t) => {
match get_status_edited_at(&mastodon, t.toot_id).await {
None => Some(t.toot_id),
Some(d) => {
// a date has been found
if d > t.datetime.unwrap() {
// said date is posterior to the previously
// written tweet, we need to delete/rewrite
for local_tweet_id in read_all_tweet_state(&conn, t.toot_id)
.unwrap_or_else(|e| {
panic!(
"Cannot fetch all tweets associated with Toot ID {}: {}",
t.toot_id, e
)
})
.into_iter()
{
delete_tweet(&config.twitter, local_tweet_id)
.await
.unwrap_or_else(|e| {
panic!("Cannot delete Tweet ID ({}): {}", t.tweet_id, e)
});
}
delete_state(&conn, t.toot_id).unwrap_or_else(|e| {
panic!("Cannot delete Toot ID ({}): {}", t.toot_id, e)
});
read_state(&conn, None)
.unwrap_or_else(|e| panic!("Cannot get last toot id: {}", e))
.map(|a| a.toot_id)
} else {
Some(t.toot_id)
}
}
}
}
};
let timeline = get_mastodon_timeline_since(&mastodon, last_toot_id)
.await
.unwrap_or_else(|e| panic!("Cannot get instance: {}", e));
@@ -57,9 +97,22 @@ pub async fn run(config: &Config) {
// if the toot is too long, we cut it in half here
if let Some((first_half, second_half)) = generate_multi_tweets(&tweet_content) {
tweet_content = second_half;
// post the first half
let reply_id = post_tweet(&config.twitter, first_half, vec![], reply_to, None)
.await
.unwrap_or_else(|e| panic!("Cannot post the first half of {}: {}", &toot.id, e));
// write it to db
write_state(
&conn,
TweetToToot {
tweet_id: reply_id,
toot_id: toot.id.parse::<u64>().unwrap(),
datetime: None,
},
)
.unwrap_or_else(|e| {
panic!("Cannot store Toot/Tweet ({}/{}): {}", &toot.id, reply_id, e)
});
reply_to = Some(reply_id);
};
@@ -80,6 +133,7 @@ pub async fn run(config: &Config) {
TweetToToot {
tweet_id,
toot_id: toot.id.parse::<u64>().unwrap(),
datetime: None,
},
)
.unwrap_or_else(|e| panic!("Cannot store Toot/Tweet ({}/{}): {}", &toot.id, tweet_id, e));

View File

@@ -49,6 +49,21 @@ fn main() {
.display_order(1),
),
)
.subcommand(
Command::new("migrate")
.version(env!("CARGO_PKG_VERSION"))
.about("Command to register to Mastodon Instance")
.arg(
Arg::new("config")
.short('c')
.long("config")
.value_name("CONFIG_FILE")
.help(format!("TOML config file for {}", env!("CARGO_PKG_NAME")))
.num_args(1)
.default_value(DEFAULT_CONFIG_PATH)
.display_order(1),
),
)
.get_matches();
env_logger::init();
@@ -63,6 +78,11 @@ fn main() {
register(sub_m.get_one::<String>("host").unwrap());
return;
}
Some(("migrate", sub_m)) => {
let config = parse_toml(sub_m.get_one::<String>("config").unwrap());
migrate_db(&config.oolatoocs.db_path).unwrap();
return;
}
_ => (),
}

View File

@@ -1,4 +1,5 @@
use crate::config::MastodonConfig;
use chrono::{DateTime, Utc};
use megalodon::{
entities::{Status, StatusVisibility},
generator,
@@ -10,16 +11,29 @@ use megalodon::{
use std::error::Error;
use std::io::stdin;
pub async fn get_mastodon_timeline_since(
config: &MastodonConfig,
id: Option<u64>,
) -> Result<Vec<Status>, Box<dyn Error>> {
let mastodon = Mastodon::new(
/// Get Mastodon Object instance
pub fn get_mastodon_instance(config: &MastodonConfig) -> Mastodon {
Mastodon::new(
config.base.to_string(),
Some(config.token.to_string()),
None,
);
)
}
/// Get the edited_at field from the specified toot
pub async fn get_status_edited_at(mastodon: &Mastodon, t: u64) -> Option<DateTime<Utc>> {
mastodon
.get_status(t.to_string())
.await
.ok()
.and_then(|t| t.json.edited_at)
}
/// Get the home timeline since the last toot
pub async fn get_mastodon_timeline_since(
mastodon: &Mastodon,
id: Option<u64>,
) -> Result<Vec<Status>, Box<dyn Error>> {
let input_options = GetHomeTimelineInputOptions {
only_media: Some(false),
limit: None,

View File

@@ -1,3 +1,4 @@
use chrono::{DateTime, Utc};
use log::debug;
use rusqlite::{params, Connection, OptionalExtension};
use std::error::Error;
@@ -7,6 +8,34 @@ use std::error::Error;
pub struct TweetToToot {
pub tweet_id: u64,
pub toot_id: u64,
pub datetime: Option<DateTime<Utc>>,
}
/// Deletes a given state
pub fn delete_state(conn: &Connection, toot_id: u64) -> Result<(), Box<dyn Error>> {
debug!("Deleting Toot ID {}", toot_id);
conn.execute(
&format!("DELETE FROM tweet_to_toot WHERE toot_id = {}", toot_id),
[],
)?;
Ok(())
}
/// Retrieves all tweets associated to a toot in the form of a vector
pub fn read_all_tweet_state(conn: &Connection, toot_id: u64) -> Result<Vec<u64>, Box<dyn Error>> {
let query = format!(
"SELECT tweet_id FROM tweet_to_toot WHERE toot_id = {};",
toot_id
);
let mut stmt = conn.prepare(&query)?;
let mut rows = stmt.query([])?;
let mut v = Vec::new();
while let Some(row) = rows.next()? {
v.push(row.get(0)?);
}
Ok(v)
}
/// if None is passed, read the last tweet from DB
@@ -17,8 +46,10 @@ pub fn read_state(
) -> Result<Option<TweetToToot>, Box<dyn Error>> {
debug!("Reading toot_id {:?}", s);
let query: String = match s {
Some(i) => format!("SELECT * FROM tweet_to_toot WHERE toot_id = {i}"),
None => "SELECT * FROM tweet_to_toot ORDER BY toot_id DESC LIMIT 1".to_string(),
Some(i) => format!(
"SELECT tweet_id, toot_id, UNIXEPOCH(datetime) AS datetime FROM tweet_to_toot WHERE toot_id = {i} ORDER BY tweet_id DESC LIMIT 1"
),
None => "SELECT tweet_id, toot_id, UNIXEPOCH(datetime) AS datetime FROM tweet_to_toot ORDER BY toot_id DESC LIMIT 1".to_string(),
};
let mut stmt = conn.prepare(&query)?;
@@ -28,6 +59,7 @@ pub fn read_state(
Ok(TweetToToot {
tweet_id: row.get("tweet_id")?,
toot_id: row.get("toot_id")?,
datetime: Some(DateTime::from_timestamp(row.get("datetime").unwrap(), 0).unwrap()),
})
})
.optional()?;
@@ -56,8 +88,9 @@ pub fn init_db(d: &str) -> Result<(), Box<dyn Error>> {
conn.execute(
"CREATE TABLE IF NOT EXISTS tweet_to_toot (
tweet_id INTEGER,
toot_id INTEGER PRIMARY KEY
tweet_id INTEGER PRIMARY KEY,
toot_id INTEGER,
datetime INTEGER DEFAULT CURRENT_TIMESTAMP
)",
[],
)?;
@@ -65,6 +98,56 @@ pub fn init_db(d: &str) -> Result<(), Box<dyn Error>> {
Ok(())
}
/// Migrate DB from 1.5.x to 1.6.x
pub fn migrate_db(d: &str) -> Result<(), Box<dyn Error>> {
debug!("Migration DB for Oolatoocs");
let conn = Connection::open(d)?;
let res = conn.execute("SELECT datetime from tweet_to_toot;", []);
// If the column can be selected then, its OK
// if not, see if the error is a missing column and add it
match res {
Err(e) => match e.to_string().as_str() {
"no such column: datetime" => migrate_db_alter_table(&conn), //column does not exist
"Execute returned results - did you mean to call query?" => Ok(()), // return results,
// column does
// exist
_ => Err(e.into()),
},
Ok(_) => Ok(()),
}
}
/// Creates a new table, copy the data from the old table and rename it
fn migrate_db_alter_table(c: &Connection) -> Result<(), Box<dyn Error>> {
// create the new table
c.execute(
"CREATE TABLE IF NOT EXISTS tweet_to_toot_new (
tweet_id INTEGER PRIMARY KEY,
toot_id INTEGER,
datetime INTEGER DEFAULT CURRENT_TIMESTAMP
)",
[],
)?;
// copy data from the old table
c.execute(
"INSERT INTO tweet_to_toot_new (tweet_id, toot_id)
SELECT tweet_id, toot_id FROM tweet_to_toot;",
[],
)?;
// drop the old table
c.execute("DROP TABLE tweet_to_toot;", [])?;
// rename the new table
c.execute("ALTER TABLE tweet_to_toot_new RENAME TO tweet_to_toot;", [])?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
@@ -119,17 +202,25 @@ mod tests {
let t_in = TweetToToot {
tweet_id: 123456789,
toot_id: 987654321,
datetime: None,
};
write_state(&conn, t_in).unwrap();
let mut stmt = conn.prepare("SELECT * FROM tweet_to_toot;").unwrap();
let mut stmt = conn
.prepare(
"SELECT tweet_id, toot_id, UNIXEPOCH(datetime) AS datetime FROM tweet_to_toot;",
)
.unwrap();
let t_out = stmt
.query_row([], |row| {
Ok(TweetToToot {
tweet_id: row.get("tweet_id").unwrap(),
toot_id: row.get("toot_id").unwrap(),
datetime: Some(
DateTime::from_timestamp(row.get("datetime").unwrap(), 0).unwrap(),
),
})
})
.unwrap();
@@ -226,4 +317,180 @@ mod tests {
assert_eq!(t_out.tweet_id, 100);
assert_eq!(t_out.toot_id, 1000);
}
#[test]
fn test_last_toot_id_read_state() {
let d = "/tmp/test_last_toot_id_read_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot(tweet_id, toot_id)
VALUES (100, 1000), (101, 1000);",
[],
)
.unwrap();
let t_out = read_state(&conn, Some(1000)).unwrap().unwrap();
remove_file(d).unwrap();
assert_eq!(t_out.tweet_id, 101);
assert_eq!(t_out.toot_id, 1000);
}
#[test]
fn test_migrate_db_alter_table() {
let d = "/tmp/test_migrate_db_alter_table.sqlite";
let conn = Connection::open(d).unwrap();
init_db(d).unwrap();
write_state(
&conn,
TweetToToot {
tweet_id: 0,
toot_id: 0,
datetime: None,
},
)
.unwrap();
write_state(
&conn,
TweetToToot {
tweet_id: 1,
toot_id: 1,
datetime: None,
},
)
.unwrap();
migrate_db_alter_table(&conn).unwrap();
let mut stmt = conn.prepare("PRAGMA table_info(tweet_to_toot);").unwrap();
let mut t = stmt.query([]).unwrap();
while let Some(row) = t.next().unwrap() {
if row.get::<usize, u8>(0).unwrap() == 2 {
assert_eq!(row.get::<usize, String>(1).unwrap(), "datetime".to_string());
}
}
remove_file(d).unwrap();
}
#[test]
fn test_migrate_db() {
// this should be idempotent
let d = "/tmp/test_migrate_db.sqlite";
let conn = Connection::open(d).unwrap();
conn.execute(
"CREATE TABLE IF NOT EXISTS tweet_to_toot (
tweet_id INTEGER,
toot_id INTEGER PRIMARY KEY
)",
[],
)
.unwrap();
conn.execute("INSERT INTO tweet_to_toot VALUES (0, 0), (1, 1);", [])
.unwrap();
migrate_db(d).unwrap();
let last_state = read_state(&conn, None).unwrap().unwrap();
assert_eq!(last_state.tweet_id, 1);
assert_eq!(last_state.toot_id, 1);
migrate_db(d).unwrap(); // shouldnt do anything
remove_file(d).unwrap();
}
#[test]
fn test_delete_state() {
let d = "/tmp/test_delete_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot(tweet_id, toot_id) VALUES (0, 0);",
[],
)
.unwrap();
delete_state(&conn, 0).unwrap();
let mut stmt = conn
.prepare(
"SELECT tweet_id, toot_id, UNIXEPOCH(datetime) AS datetime FROM tweet_to_toot;",
)
.unwrap();
let t_out = stmt.query_row([], |row| {
Ok(TweetToToot {
tweet_id: row.get("tweet_id").unwrap(),
toot_id: row.get("toot_id").unwrap(),
datetime: Some(DateTime::from_timestamp(row.get("datetime").unwrap(), 0).unwrap()),
})
});
assert!(t_out.is_err_and(|x| x == rusqlite::Error::QueryReturnedNoRows));
conn.execute(
"INSERT INTO tweet_to_toot(tweet_id, toot_id) VALUES(102,42), (103,42);",
[],
)
.unwrap();
delete_state(&conn, 42).unwrap();
let mut stmt = conn
.prepare(
"SELECT tweet_id, toot_id, UNIXEPOCH(datetime) AS datetime FROM tweet_to_toot;",
)
.unwrap();
let t_out = stmt.query_row([], |row| {
Ok(TweetToToot {
tweet_id: row.get("tweet_id").unwrap(),
toot_id: row.get("toot_id").unwrap(),
datetime: Some(DateTime::from_timestamp(row.get("datetime").unwrap(), 0).unwrap()),
})
});
assert!(t_out.is_err_and(|x| x == rusqlite::Error::QueryReturnedNoRows));
remove_file(d).unwrap();
}
#[test]
fn test_read_all_tweet_state() {
let d = "/tmp/read_all_tweet_state.sqlite";
init_db(d).unwrap();
let conn = Connection::open(d).unwrap();
conn.execute(
"INSERT INTO tweet_to_toot(tweet_id, toot_id) VALUES (102, 42), (103, 42), (105, 43);",
[],
)
.unwrap();
let v1 = read_all_tweet_state(&conn, 43).unwrap();
let v2 = read_all_tweet_state(&conn, 42).unwrap();
assert_eq!(v1, vec![105]);
assert_eq!(v2, vec![102, 103]);
remove_file(d).unwrap();
}
}

View File

@@ -113,6 +113,35 @@ fn get_token(config: &TwitterConfig) -> Token {
)
}
/// This functions deletes a tweet, given its id
pub async fn delete_tweet(config: &TwitterConfig, id: u64) -> Result<(), Box<dyn Error>> {
debug!("Deleting Tweet {}", id);
let empty_request = EmptyRequest {}; // Why? Because fuck you, thats why!
let token = get_token(config);
let client = Client::new();
let res = client
.delete(format!("{}/{}", TWITTER_API_TWEET_URL, id))
.header(
"Authorization",
oauth1_request::delete(
format!("{}/{}", TWITTER_API_TWEET_URL, id),
&empty_request,
&token,
oauth1_request::HMAC_SHA1,
),
)
.send()
.await?;
if !res.status().is_success() {
return Err(OolatoocsError::new(&format!("Cannot delete Tweet {}", id)).into());
}
Ok(())
}
/// This function generates a media_ids vec to be used by Twitter
pub async fn generate_media_ids(config: &TwitterConfig, media_attach: &[Attachment]) -> Vec<u64> {
let mut medias: Vec<u64> = vec![];