From 4b0f62be8d3424e8ea97ba3a1a4a06c0c142b58f Mon Sep 17 00:00:00 2001 From: Sokhibjon Orzikulov Date: Sat, 18 Nov 2023 01:26:06 +0500 Subject: [PATCH] adding version & latest version checker --- Cargo.lock | 450 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + delta/latest.ts | 28 --- delta/mod.ts | 4 - delta/version.ts | 91 -------- src/functions/groups.rs | 18 +- src/functions/latest.rs | 38 ++++ src/functions/mod.rs | 14 +- src/functions/version.rs | 118 ++++++++++ src/lib.rs | 6 + src/main.rs | 6 +- src/utils/github.rs | 65 ++++++ src/utils/group_manager.rs | 6 +- src/utils/mod.rs | 1 + 14 files changed, 712 insertions(+), 134 deletions(-) delete mode 100644 delta/latest.ts delete mode 100644 delta/version.ts create mode 100644 src/functions/latest.rs create mode 100644 src/functions/version.rs create mode 100644 src/utils/github.rs diff --git a/Cargo.lock b/Cargo.lock index c932230..427aee8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "aquamarine" version = "0.1.12" @@ -39,6 +54,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -111,8 +143,11 @@ version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ + "android-tzdata", + "iana-time-zone", "num-traits", "serde", + "windows-targets", ] [[package]] @@ -189,6 +224,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -202,6 +246,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "dptree" version = "0.3.0" @@ -466,6 +516,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -508,6 +564,34 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -521,6 +605,29 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -553,6 +660,16 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "iri-string" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -588,6 +705,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155c4d7e39ad04c172c5e3a99c434ea3b4a7ba7960b38ecd562b270b097cce09" +dependencies = [ + "base64", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -678,6 +809,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -706,6 +858,43 @@ dependencies = [ "memchr", ] +[[package]] +name = "octocrab" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfeeafb5fa0da7046229ec3c7b3bd2981aae05c549871192c408d59fc0fffd5" +dependencies = [ + "arc-swap", + "async-trait", + "base64", + "bytes", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls", + "hyper-timeout", + "jsonwebtoken", + "once_cell", + "percent-encoding", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "snafu", + "tokio", + "tower", + "tower-http", + "tracing", + "url", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -756,6 +945,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "pem" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923" +dependencies = [ + "base64", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -800,6 +999,12 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "pretty_env_logger" version = "0.5.0" @@ -940,6 +1145,20 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -961,6 +1180,7 @@ version = "0.1.0" dependencies = [ "crates_io_api", "log", + "octocrab", "pretty_env_logger", "serde", "serde_json", @@ -983,6 +1203,49 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustls" +version = "0.21.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629648aced5775d558af50b2b4c7b02983a04b312126d45eeead26e7caa498b9" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.15" @@ -1004,6 +1267,25 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -1107,6 +1389,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -1116,6 +1410,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "socket2" version = "0.4.10" @@ -1136,6 +1453,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "strsim" version = "0.10.0" @@ -1308,6 +1631,35 @@ dependencies = [ "syn 2.0.39", ] +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1341,6 +1693,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-macros" version = "2.2.0" @@ -1362,6 +1724,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -1387,6 +1759,50 @@ 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", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "iri-string", + "pin-project-lite", + "tower", + "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" @@ -1399,10 +1815,23 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1448,6 +1877,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.4.1" @@ -1616,6 +2051,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1691,3 +2135,9 @@ dependencies = [ "cfg-if", "windows-sys", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 3c17fb6..f1a754b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ crates_io_api = "0.8.2" uuid = { version = "1.5.0", features = ["v4"] } serde_json = "1.0.108" serde = { version = "1.0.192", features = ["derive"] } +octocrab = { version = "0.32.0" } diff --git a/delta/latest.ts b/delta/latest.ts deleted file mode 100644 index 38d30b3..0000000 --- a/delta/latest.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Composer, Context, InlineKeyboard } from "../deps.ts"; -import type { Release } from "../types/Github.d.ts"; -import { last } from "../utils/generator.ts"; -import hecker from "../utils/checker.ts"; -import { reply } from "../utils/sender.ts"; - -const composer = new Composer(); - -export const message = async (data: Release) => - // make a message about the release date of the new release - `Hozirgi eng oxirgi versiya bu ${data.tag_name} va ushbu reliz ${ - new Date(data.published_at).toLocaleDateString("uz") - } da e'lon qilingan ${data.author.login} tomonidan` + - `\n` + - `\n` + - `Ushbu oxirgi relizni o'rnatish uchun terminalingizda rustup update buyrug'ini ishga tushuring!`; - -export const keyboard = (data: Release) => - new InlineKeyboard().url("Ko'proq ma'lumotlar", data.html_url); - -composer.command("last", async (ctx: Context): Promise => { - const req = await last(); - await reply(ctx, await message(req), keyboard(req)); -}); - -export default composer; diff --git a/delta/mod.ts b/delta/mod.ts index bc91709..d760e89 100644 --- a/delta/mod.ts +++ b/delta/mod.ts @@ -3,15 +3,11 @@ import { Bot } from "../deps.ts"; import channel from "./channel.ts"; import trigger from "./trigger.ts"; import useful from "./useful.ts"; -import latest from "./latest.ts"; -import version from "./version.ts"; export default async (bot: Bot) => { await bot .use(which) .use(useful) - .use(latest) - .use(version) .use(trigger) .use(channel); }; diff --git a/delta/version.ts b/delta/version.ts deleted file mode 100644 index ef5a680..0000000 --- a/delta/version.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Composer, Context, InlineKeyboard } from "../deps.ts"; -import { finder, pager as generator } from "../utils/generator.ts"; -import hecker from "../utils/checker.ts"; -import { reply } from "../utils/sender.ts"; - -const composer = new Composer(); -const ctxMenuText = "Rust Dasturlash tili versiyalari:"; - -composer.command("version", async (ctx: Context): Promise => { - const keyboard = new InlineKeyboard(); - - for (const release of await generator(1)) { - keyboard.text( - release.tag_name, - `changelog_${1}_${release.id}`, - ).row(); - } - - if ((await generator(2)).length > 0) { - keyboard.text(`Keyingi ➡️`, `version_2`); - } - - await reply(ctx, ctxMenuText, keyboard, { - disable_web_page_preview: true, - }); -}); - -composer.callbackQuery(/^version_(\d+)$/, async (ctx: Context) => { - const page = Number(ctx.match![1]); - const keyboard = new InlineKeyboard(); - - for (const release of await generator(page)) { - keyboard.text( - release.tag_name, - `changelog_${page}_${release.id}`, - ).row(); - } - - if (page > 1) { - keyboard.text(`⬅️ Oldingi`, `version_${page - 1}`); - } - - if ((await generator(page + 1)).length > 0) { - keyboard.text(`Keyingi ➡️`, `version_${page + 1}`); - } - - await ctx.editMessageText(ctxMenuText, { - parse_mode: "HTML", - reply_markup: keyboard, - disable_web_page_preview: true, - }); -}); - -composer.callbackQuery(/^changelog_(\d+)_(\d+)$/, async (ctx: Context) => { - const keyboard = new InlineKeyboard(); - const page = Number(ctx.match![1]); - const data = await finder(Number(ctx.match![2])); - - keyboard.url( - `📝 GitHub da o'qish`, - data.html_url, - ); - - keyboard.row().text(`🔙 Orqaga`, `version_${page}`); - - await ctx.editMessageText( - `${data.name}` + - `\n` + - `\n` + - `Yaratildi: ${ - new Date(data.created_at).toLocaleDateString("uz") - }` + - `\n` + - `E'lon qilindi: ${ - new Date(data.published_at).toLocaleDateString("uz") - }` + - `\n` + - `O'rnatish: rustup install ${data.tag_name}` + - `\n` + - `\n` + - `"Instant view" yoki quyidagi tugma orqali ko'proq ma'lumot oling:`, - { - parse_mode: "HTML", - reply_markup: keyboard, - }, - ); -}); - -export default composer; diff --git a/src/functions/groups.rs b/src/functions/groups.rs index 316d0d6..fc89106 100644 --- a/src/functions/groups.rs +++ b/src/functions/groups.rs @@ -1,4 +1,7 @@ -use crate::utils::{group_manager::{Groups, Group}, keyboard_manager::Keyboard}; +use crate::utils::{ + group_manager::{Group, Groups}, + keyboard_manager::Keyboard, +}; use teloxide::{ payloads::SendMessageSetters, prelude::*, @@ -44,7 +47,7 @@ pub async fn callback_detail(bot: &Bot, q: &CallbackQuery, args: &Vec<&str>) -> if let Some(Message { id, chat, .. }) = q.message.clone() { bot.edit_message_text(chat.id, id, view_detail(&find)) .parse_mode(ParseMode::Html) - .reply_markup(keyboard_detail( args[0].parse().unwrap_or(1), &find)) + .reply_markup(keyboard_detail(args[0].parse().unwrap_or(1), &find)) .await?; } else if let Some(id) = q.inline_message_id.clone() { bot.edit_message_text_inline(id, "Oopsie, something went wrong...") @@ -58,11 +61,12 @@ pub async fn callback_detail(bot: &Bot, q: &CallbackQuery, args: &Vec<&str>) -> pub fn view_detail(data: &Option) -> String { match data { Some(d) => { - format!("{}\n\n{}\n\nUse the following buttons to get to the links:", d.name, d.about) - }, - None => { - "Ushbu guruh mavjud emas!".to_string() + format!( + "{}\n\n{}\n\nUse the following buttons to get to the links:", + d.name, d.about + ) } + None => "Ushbu guruh mavjud emas!".to_string(), } } @@ -97,7 +101,7 @@ pub fn keyboard_detail(page: i32, data: &Option) -> InlineKeyboardMarkup if let Some(group) = data { keyboard.url("Telegram", &format!("https://t.me/{}", group.telegram)); - + if group.link.is_some() { keyboard.url("Web", &group.link.clone().unwrap()); } diff --git a/src/functions/latest.rs b/src/functions/latest.rs new file mode 100644 index 0000000..e69b8d5 --- /dev/null +++ b/src/functions/latest.rs @@ -0,0 +1,38 @@ +use crate::utils::{github::GitHub, keyboard_manager::Keyboard}; +use octocrab::models::repos::Release; +use teloxide::{ + payloads::SendMessageSetters, + prelude::*, + types::{InlineKeyboardMarkup, ParseMode}, +}; + +pub async fn command(bot: &Bot, github: GitHub, msg: &Message) -> ResponseResult<()> { + let latest = github.get_latest().await.unwrap(); + + bot.send_message(msg.chat.id, view(&latest)) + .parse_mode(ParseMode::Html) + .reply_markup(keyboard(&latest)) + .await?; + + Ok(()) +} + +pub fn view(release: &Release) -> String { + format!( + "Hozirgi eng oxirgi versiya bu \ + {} va ushbu reliz {} da e'lon qilingan \ + {} tomonidan.\ + \n\n\ + ", + format!("https://releases.rs/docs/{}", release.tag_name), + release.tag_name, + release.published_at.unwrap().date_naive(), + release.author.html_url, + release.author.login, + ) +} + +pub fn keyboard(release: &Release) -> InlineKeyboardMarkup { + let mut keyboard = Keyboard::new(); + keyboard.url("Ko'proq ma'lumotlar", release.html_url.as_str()) +} diff --git a/src/functions/mod.rs b/src/functions/mod.rs index 627bc5c..3990967 100644 --- a/src/functions/mod.rs +++ b/src/functions/mod.rs @@ -2,11 +2,14 @@ pub mod about; pub mod groups; pub mod help; pub mod inline; +pub mod latest; pub mod rules; pub mod start; +pub mod version; pub use inline::inline; +use crate::utils::github::GitHub; use crate::Command; use std::error::Error; use teloxide::prelude::*; @@ -16,6 +19,7 @@ pub async fn commands( _me: teloxide::types::Me, msg: Message, cmd: Command, + github: GitHub, ) -> Result<(), Box> { let _ = match cmd { Command::Start => crate::functions::start::command(&bot, &msg).await, @@ -23,12 +27,18 @@ pub async fn commands( Command::Rules => crate::functions::rules::command(&bot, &msg).await, Command::About => crate::functions::about::command(&bot, &msg).await, Command::Groups => crate::functions::groups::command(&bot, &msg).await, + Command::Latest => crate::functions::latest::command(&bot, github, &msg).await, + Command::Version => crate::functions::version::command(&bot, github, &msg).await, }; Ok(()) } -pub async fn callback(bot: Bot, q: CallbackQuery) -> Result<(), Box> { +pub async fn callback( + bot: Bot, + q: CallbackQuery, + github: GitHub, +) -> Result<(), Box> { let mut args: Vec<&str> = Vec::new(); if let Some(data) = q.data.clone() { @@ -41,6 +51,8 @@ pub async fn callback(bot: Bot, q: CallbackQuery) -> Result<(), Box crate::functions::groups::callback_list(&bot, &q, &args).await, "detail" => crate::functions::groups::callback_detail(&bot, &q, &args).await, + "version" => crate::functions::version::callback_list(&bot, &q, &args, github).await, + "changelog" => crate::functions::version::callback_detail(&bot, &q, &args, github).await, _ => Ok(()), }; } diff --git a/src/functions/version.rs b/src/functions/version.rs new file mode 100644 index 0000000..db4c6bd --- /dev/null +++ b/src/functions/version.rs @@ -0,0 +1,118 @@ +use crate::utils::{github::GitHub, keyboard_manager::Keyboard}; +use octocrab::models::repos::Release; +use teloxide::{ + payloads::SendMessageSetters, + prelude::*, + types::{InlineKeyboardMarkup, ParseMode}, +}; + +static TEXT: &str = "Rust Dasturlash tili versiyalari:"; + +pub async fn command(bot: &Bot, github: GitHub, msg: &Message) -> ResponseResult<()> { + let versions = github.get_list(1).await.unwrap(); + let next_page = github.get_list(2).await.unwrap(); + + bot.send_message(msg.chat.id, TEXT) + .parse_mode(ParseMode::Html) + .reply_markup(keyboard_list(1, versions, Some(next_page))) + .await?; + + Ok(()) +} + +pub async fn callback_list( + bot: &Bot, + q: &CallbackQuery, + args: &Vec<&str>, + github: GitHub, +) -> ResponseResult<()> { + let page = args[0].parse::().unwrap(); + let versions: Vec = github.get_list(page).await.unwrap(); + let next_page = github.get_list(page + 1).await.unwrap(); + + if !args.is_empty() { + if let Some(Message { id, chat, .. }) = q.message.clone() { + bot.edit_message_text(chat.id, id, TEXT) + .parse_mode(ParseMode::Html) + .reply_markup(keyboard_list(page, versions, Some(next_page))) + .await?; + } else if let Some(id) = q.inline_message_id.clone() { + bot.edit_message_text_inline(id, "Oopsie, something went wrong...") + .await?; + } + } + + Ok(()) +} + + +pub async fn callback_detail(bot: &Bot, q: &CallbackQuery, args: &Vec<&str>, github: GitHub) -> ResponseResult<()> { + let page = args[0].parse::().unwrap(); + let version: Release = github.get_detail(args[1]).await.unwrap(); + + if !args.is_empty() { + if let Some(Message { id, chat, .. }) = q.message.clone() { + bot.edit_message_text(chat.id, id, view_detail(&version)) + .parse_mode(ParseMode::Html) + .reply_markup(keyboard_detail(page, version)) + .await?; + } else if let Some(id) = q.inline_message_id.clone() { + bot.edit_message_text_inline(id, "Oopsie, something went wrong...") + .await?; + } + } + + Ok(()) +} + +pub fn view_detail(release: &Release) -> String { + format!( + "{}\n\n\ + Yaratildi: {}\n\ + E'lon qilindi: {}\n\ + O'rnatish: rustup install {}\n\n\ + \"Instant view\" yoki quyidagi tugma orqali ko'proq ma'lumot oling:", + release.html_url, + release.name.clone().unwrap(), + release.created_at.unwrap().format("%d.%m.%Y"), + release.published_at.unwrap().format("%d.%m.%Y"), + release.tag_name + ) +} + +pub fn keyboard_list( + page: u32, + releases: Vec, + next_page: Option>, +) -> InlineKeyboardMarkup { + let mut keyboard = Keyboard::new(); + + for release in releases { + keyboard.text(&release.tag_name, &format!("changelog_{}_{}", page, release.tag_name)); + keyboard.row(); + } + + if page > 1 { + keyboard.text("⬅️ Oldingi", &format!("version_{}", page - 1)); + } + + if next_page.is_some() && !next_page.unwrap().is_empty() { + keyboard.text("Keyingi ➡️", &format!("version_{}", page + 1)); + } + + keyboard.get() +} + +pub fn keyboard_detail( + page: u32, + release: Release, +) -> InlineKeyboardMarkup { + let mut keyboard = Keyboard::new(); + + keyboard.url("📝 GitHub da o'qish", release.html_url.as_str()); + keyboard.row(); + keyboard.text("🔙 Orqaga", &format!("version_{}", page)); + + keyboard.get() +} + diff --git a/src/lib.rs b/src/lib.rs index d690ac6..f45474b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,12 @@ pub enum Command { /// Available groups Groups, + + /// Latest version + Latest, + + /// Specific version + Version, } pub fn handler() -> UpdateHandler> { diff --git a/src/main.rs b/src/main.rs index 80099d7..864af7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use crates_io_api::AsyncClient; -use rustina::handler; +use rustina::{handler, utils::github::GitHub}; use std::error::Error; use teloxide::prelude::*; @@ -16,8 +16,10 @@ async fn main() -> Result<(), Box> { ) .unwrap(); + let github = GitHub::new(); + Dispatcher::builder(bot, handler()) - .dependencies(dptree::deps![crates_client]) + .dependencies(dptree::deps![crates_client, github]) // If no handler succeeded to handle an update, this closure will be called .default_handler(|upd| async move { log::warn!("Unhandled update: {:?}", upd); diff --git a/src/utils/github.rs b/src/utils/github.rs new file mode 100644 index 0000000..3f984f5 --- /dev/null +++ b/src/utils/github.rs @@ -0,0 +1,65 @@ +use octocrab::{models::repos::Release, Octocrab}; +use std::error::Error; + +#[derive(Clone, Debug)] +pub struct GitHub { + client: Octocrab, +} + +impl GitHub { + pub fn new() -> Self { + Self { + client: Octocrab::builder() + .add_header( + "User-Agent".parse().unwrap(), + "Rustina Assistant (rust@maid.uz)".to_string(), + ) + .add_header( + "Authorization".parse().unwrap(), + std::env::var("GITHUB_TOKEN").unwrap(), + ) + .build() + .unwrap(), + } + } + + pub async fn get_latest(&self) -> Result> { + let latest = self + .client + .repos("rust-lang", "rust") + .releases() + .get_latest() + .await?; + + Ok(latest) + } + + pub async fn get_list(&self, page: u32) -> Result, Box> { + let versions = self + .client + .repos("rust-lang", "rust") + .releases() + .list() + .per_page(5) + .page(page) + .send() + .await? + .take_items(); + + Ok(versions) + } + + pub async fn get_detail( + &self, + tag_name: &str, + ) -> Result> { + let detail = self + .client + .repos("rust-lang", "rust") + .releases() + .get_by_tag(tag_name) + .await?; + + Ok(detail) + } +} diff --git a/src/utils/group_manager.rs b/src/utils/group_manager.rs index 11179dd..b3c240c 100644 --- a/src/utils/group_manager.rs +++ b/src/utils/group_manager.rs @@ -42,7 +42,11 @@ impl Groups { } pub fn find_group(&self, query: String) -> Option { - let search: Vec<&Group> = self.groups.iter().filter(|group| group.telegram[1..] == query).collect(); + let search: Vec<&Group> = self + .groups + .iter() + .filter(|group| group.telegram[1..] == query) + .collect(); if search.is_empty() { return None; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 39d3ae4..701861c 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,3 +1,4 @@ +pub mod github; pub mod group_manager; pub mod inline_manager; pub mod keyboard_manager;