From c66fdacaaa5a3a09cf52ac2b60886d78235cbe44 Mon Sep 17 00:00:00 2001 From: Heliozoa Date: Wed, 5 Jul 2023 08:35:36 +0300 Subject: [PATCH] Progress on implementing mooc support --- Cargo.lock | 962 +++++++++++++----------- Cargo.toml | 31 +- rustfmt.toml | 4 +- src/cli.rs | 64 +- src/commands.rs | 18 +- src/commands/courses.rs | 25 +- src/commands/download.rs | 5 +- src/commands/exercises.rs | 21 +- src/commands/login.rs | 18 +- src/commands/mooc.rs | 63 ++ src/commands/mooc/course_exercises.rs | 34 + src/commands/mooc/courses.rs | 25 + src/commands/mooc/download_exercises.rs | 107 +++ src/commands/mooc/submit_exercise.rs | 26 + src/commands/paste.rs | 2 +- src/commands/submit.rs | 5 +- src/commands/util.rs | 179 +++-- src/config.rs | 69 ++ src/lib.rs | 1 + src/updater.rs | 4 +- taplo.toml | 13 + 21 files changed, 1143 insertions(+), 533 deletions(-) create mode 100644 src/commands/mooc.rs create mode 100644 src/commands/mooc/course_exercises.rs create mode 100644 src/commands/mooc/courses.rs create mode 100644 src/commands/mooc/download_exercises.rs create mode 100644 src/commands/mooc/submit_exercise.rs create mode 100644 src/config.rs create mode 100644 taplo.toml diff --git a/Cargo.lock b/Cargo.lock index 2aa73dd..1edc7a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -19,25 +19,30 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aes" -version = "0.7.5" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" dependencies = [ "cfg-if", "cipher", "cpufeatures", - "opaque-debug", ] [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" 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" @@ -49,9 +54,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e579a7752471abc2a8268df8b20005e3eadd975f585398f17efcfd8d4927371" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" dependencies = [ "anstyle", "anstyle-parse", @@ -64,15 +69,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -88,9 +93,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcd8291a340dd8ac70e18878bc4501dd7b4ff970cfa21c207d36ece51ea88fd" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", "windows-sys 0.48.0", @@ -98,9 +103,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" dependencies = [ "backtrace", ] @@ -128,9 +133,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", @@ -149,9 +154,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "base64ct" @@ -165,6 +170,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "block-buffer" version = "0.10.4" @@ -176,9 +187,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" dependencies = [ "memchr", "once_cell", @@ -188,9 +199,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -254,13 +265,13 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", "time 0.1.45", @@ -270,18 +281,19 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common", + "inout", ] [[package]] name = "clap" -version = "4.2.2" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b802d85aaf3a1cdb02b224ba472ebdea62014fccfcb269b95a4d76443b5ee5a" +checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a" dependencies = [ "clap_builder", "clap_derive", @@ -290,53 +302,42 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.2.2" +version = "4.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14a1a858f532119338887a4b8e1af9c60de8249cd7bafd68036a489e261e37b6" +checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d" dependencies = [ "anstream", "anstyle", - "bitflags", "clap_lex", "strsim", ] [[package]] name = "clap_complete" -version = "4.2.0" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c22dcfb410883764b29953103d9ef7bb8fe21b3fa1158bc99986c2067294bd" +checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.2.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.23", ] [[package]] name = "clap_lex" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" - -[[package]] -name = "codespan-reporting" -version = "0.11.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "colorchoice" @@ -346,15 +347,15 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" -version = "0.15.5" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -363,6 +364,34 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.22", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d606d0fba62e13cf04db20536c05cb7f13673c161cb47a47a82b9b9e7d3f1daa" +dependencies = [ + "cookie", + "idna 0.2.3", + "log", + "publicsuffix", + "serde", + "serde_derive", + "serde_json", + "time 0.3.22", + "url", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -371,9 +400,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -389,9 +418,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -402,7 +431,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", @@ -418,7 +447,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crossterm_winapi", "libc", "mio", @@ -430,9 +459,9 @@ dependencies = [ [[package]] name = "crossterm_winapi" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ "winapi", ] @@ -447,50 +476,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.15", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - [[package]] name = "difflib" version = "0.4.0" @@ -499,9 +484,9 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -510,22 +495,23 @@ dependencies = [ [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -536,9 +522,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dunce" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "dyn-clone" @@ -567,6 +553,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.3.1" @@ -599,12 +591,12 @@ dependencies = [ [[package]] name = "fd-lock" -version = "3.0.12" +version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ae6b3d9530211fb3b12a95374b8b0823be812f53d09e18c5675c0146b09642" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" dependencies = [ "cfg-if", - "rustix", + "rustix 0.38.2", "windows-sys 0.48.0", ] @@ -622,9 +614,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "miniz_oxide", @@ -632,9 +624,9 @@ dependencies = [ [[package]] name = "flexi_logger" -version = "0.25.3" +version = "0.25.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eae57842a8221ef13f1f207632d786a175dd13bd8fbdc8be9d852f7c9cf1046" +checksum = "37e7b68b1f7ce9c62856598e99cd6742b9cedb6186b47aa989a82640f20bfa9b" dependencies = [ "chrono", "glob", @@ -663,9 +655,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -676,6 +668,21 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.28" @@ -683,6 +690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -691,12 +699,34 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + [[package]] name = "futures-io" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.23", +] + [[package]] name = "futures-sink" version = "0.3.28" @@ -715,8 +745,11 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ + "futures-channel", "futures-core", "futures-io", + "futures-macro", + "futures-sink", "futures-task", "memchr", "pin-project-lite", @@ -736,9 +769,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "js-sys", @@ -749,9 +782,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "glob" @@ -761,9 +794,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -771,7 +804,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -785,25 +818,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "heck" -version = "0.4.1" +name = "hashbrown" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" [[package]] name = "hex" @@ -856,9 +886,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -880,10 +910,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -893,9 +924,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -907,12 +938,22 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -925,6 +966,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "impl-enum" version = "0.3.0" @@ -944,21 +995,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", ] [[package]] name = "indicatif" -version = "0.17.3" +version = "0.17.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" +checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" dependencies = [ "console", + "instant", "number_prefix", "portable-atomic", "unicode-width", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -970,38 +1041,37 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi", "libc", "windows-sys 0.48.0", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "is-terminal" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +checksum = "24fddda5af7e54bf7da53067d6e802dbcc381d0a8eef629df528e3ebf68755cb" dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", + "hermit-abi", + "rustix 0.38.2", "windows-sys 0.48.0", ] [[package]] name = "isolang" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64fd6448ee8a45ce6e4365c58e4fa7d8740cba2ed70db3e9ab4879ebd93eaaa" +checksum = "f80f221db1bc708b71128757b9396727c04de86968081e18e89b0575e03be071" dependencies = [ "phf", ] @@ -1017,20 +1087,21 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "62b02a5381cc465bd3041d84623d0fa3b66738b52b8e2fc3bab8ad63ab032f4a" [[package]] name = "j4rs" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc9c1648a1cc940ac10c19f56e50bee15344590e10f220899d955db5f87ac2" +checksum = "fbb7f40761e966881d96153dba31b83f012de43d12f8ab262551a99bc9651ca1" dependencies = [ "cesu8", "dirs", "dunce", "fs_extra", + "futures", "glob", "java-locator", "jni-sys", @@ -1045,9 +1116,9 @@ dependencies = [ [[package]] name = "java-locator" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cb7c9d00a642469deceff95ca37d0da9ce72d7f8b863edbebdf0aac75093da" +checksum = "90003f2fd9c52f212c21d8520f1128da0080bad6fff16b68fe6e7f2f0c3780c2" dependencies = [ "glob", "lazy_static", @@ -1070,9 +1141,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1100,40 +1171,37 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" dependencies = [ "cfg-if", - "winapi", + "windows-sys 0.48.0", ] [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.3.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1141,12 +1209,15 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "md5" @@ -1193,23 +1264,36 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "mooc-langs-api" +version = "0.1.0" +source = "git+https://github.com/rage/secret-project-331.git?branch=langs-api#e62f3ccf09a18016afe9d30b0ca83cc757173712" +dependencies = [ + "chrono", + "oauth2", + "serde", + "serde_json", + "thiserror", + "uuid", ] [[package]] @@ -1218,7 +1302,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset", @@ -1244,22 +1328,11 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "nu-ansi-term" -version = "0.46.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +checksum = "1df031e117bca634c262e9bd3173776844b6c17a90b3741c9163663b4385af76" dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", + "windows-sys 0.45.0", ] [[package]] @@ -1273,11 +1346,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "libc", ] @@ -1289,9 +1362,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "oauth2" -version = "4.3.0" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaf26a72311c087f8c5ba617c96fac67a5c04f430e716ac8d8ab2de62e23368" +checksum = "09a6e2a2b13a56ebeabba9142f911745be6456163fd6c3d361274ebcd891a80c" dependencies = [ "base64 0.13.1", "chrono", @@ -1309,30 +1382,24 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "opaque-debug" -version = "0.3.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] -name = "overload" -version = "0.1.1" +name = "option-ext" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "parking_lot" @@ -1346,15 +1413,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.1", ] [[package]] @@ -1382,33 +1449,33 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" -version = "0.10.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_shared", ] [[package]] name = "phf_shared" -version = "0.10.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -1418,15 +1485,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "portable-atomic" -version = "0.3.19" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" +checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" [[package]] name = "ppv-lite86" @@ -1467,18 +1534,34 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] +[[package]] +name = "psl-types" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" + +[[package]] +name = "publicsuffix" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a8c1bda5ae1af7f99a2962e49df150414a43d62404644d98dd5c3a93d07457" +dependencies = [ + "idna 0.3.0", + "psl-types", +] + [[package]] name = "quote" -version = "1.0.26" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" dependencies = [ "proc-macro2", ] @@ -1519,7 +1602,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1528,7 +1611,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1544,9 +1627,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -1561,18 +1644,20 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", "bytes", + "cookie", + "cookie_store", "encoding_rs", "futures-core", "futures-util", @@ -1655,44 +1740,67 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.37.11" +version = "0.37.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +checksum = "8818fa822adcc98b18fedbb3632a6a33213c070556b5aa7c4c8cc21cff565c4c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabcb0461ebd01d6b79945797c27f8529082226cb630a9865a71870ff63532a4" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.3", "windows-sys 0.48.0", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64 0.21.2", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" dependencies = [ - "base64 0.21.0", + "ring", + "untrusted", ] [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "fe232bdf6be8c8de797b22184ee71118d63780ea42ac85b61d1baa6d3b782ae9" [[package]] name = "same-file" @@ -1734,12 +1842,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" - [[package]] name = "sct" version = "0.7.0" @@ -1752,9 +1854,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.160" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "d01b7404f9d441d3ad40e6a636a7782c377d2abdbe4fa2440e2edcc2f4f10db8" dependencies = [ "serde_derive", ] @@ -1773,13 +1875,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.166" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "5dd83d6dde2b6b2d466e14d9d1acce8816dedee94f735eac6395808b3483c6d6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.23", ] [[package]] @@ -1795,9 +1897,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" dependencies = [ "itoa", "ryu", @@ -1806,18 +1908,19 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" +checksum = "0b1b6471d7496b051e03f1958802a73f88b947866f5146f329e47e36554f4e55" dependencies = [ + "itoa", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -1836,11 +1939,11 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.9.21" +version = "0.9.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" +checksum = "452e67b9c20c37fa79df53201dc03839651086ed9bbe92b3ca585ca9fdaa7d85" dependencies = [ - "indexmap", + "indexmap 2.0.0", "itoa", "ryu", "serde", @@ -1860,9 +1963,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -1970,9 +2073,9 @@ dependencies = [ [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" @@ -1987,9 +2090,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" dependencies = [ "proc-macro2", "quote", @@ -2009,15 +2112,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", + "rustix 0.37.22", + "windows-sys 0.48.0", ] [[package]] @@ -2035,7 +2139,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix", + "rustix 0.37.22", "windows-sys 0.48.0", ] @@ -2047,22 +2151,22 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "c16a64ba9387ef3fdae4f9c1a7f07a0997fce91985c0336f1ddc1822b3b37802" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "d14928354b01c4d6a4f0e549069adef399a284e7995c7ccca94e8a07a5346c59" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.23", ] [[package]] @@ -2078,19 +2182,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ + "itoa", "serde", "time-core", + "time-macros", ] [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] [[package]] name = "tinyvec" @@ -2113,6 +2228,7 @@ version = "1.1.2" dependencies = [ "anyhow", "assert_cmd", + "bytes", "clap", "clap_complete", "crossterm 0.26.1", @@ -2130,39 +2246,15 @@ dependencies = [ "toml", "tui", "url", -] - -[[package]] -name = "tmc-client" -version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" -dependencies = [ - "chrono", - "dirs", - "http", - "log", - "oauth2", - "once_cell", - "percent-encoding", - "regex", - "reqwest", - "schemars", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tmc-langs-plugins", - "tmc-langs-util", - "url", - "walkdir", + "uuid", ] [[package]] name = "tmc-langs" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", + "chrono", "dirs", "hmac", "impl-enum", @@ -2182,12 +2274,14 @@ dependencies = [ "tar", "tempfile", "thiserror", - "tmc-client", "tmc-langs-framework", "tmc-langs-plugins", "tmc-langs-util", + "tmc-mooc-client", + "tmc-testmycode-client", "toml", "url", + "uuid", "walkdir", "zip", "zstd 0.12.3+zstd.1.5.2", @@ -2196,7 +2290,6 @@ dependencies = [ [[package]] name = "tmc-langs-csharp" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "dirs", "log", @@ -2212,7 +2305,6 @@ dependencies = [ [[package]] name = "tmc-langs-framework" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "fd-lock", "isolang", @@ -2236,7 +2328,6 @@ dependencies = [ [[package]] name = "tmc-langs-java" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "dirs", "flate2", @@ -2256,7 +2347,6 @@ dependencies = [ [[package]] name = "tmc-langs-make" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "log", "once_cell", @@ -2273,7 +2363,6 @@ dependencies = [ [[package]] name = "tmc-langs-notests" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "log", "tmc-langs-framework", @@ -2284,7 +2373,6 @@ dependencies = [ [[package]] name = "tmc-langs-plugins" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "impl-enum", "log", @@ -2306,7 +2394,6 @@ dependencies = [ [[package]] name = "tmc-langs-python3" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "dunce", "hex", @@ -2327,7 +2414,6 @@ dependencies = [ [[package]] name = "tmc-langs-r" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "log", "serde", @@ -2341,7 +2427,6 @@ dependencies = [ [[package]] name = "tmc-langs-util" version = "0.31.2" -source = "git+https://github.com/rage/tmc-langs-rust/#b09351d8a0d6c6e32435e4f5ba5e6db1c8168230" dependencies = [ "dunce", "fd-lock", @@ -2360,38 +2445,79 @@ dependencies = [ "winapi", ] +[[package]] +name = "tmc-mooc-client" +version = "0.31.2" +dependencies = [ + "bytes", + "chrono", + "log", + "mooc-langs-api", + "oauth2", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tmc-langs-util", + "uuid", +] + +[[package]] +name = "tmc-testmycode-client" +version = "0.31.2" +dependencies = [ + "chrono", + "dirs", + "http", + "log", + "oauth2", + "once_cell", + "percent-encoding", + "regex", + "reqwest", + "schemars", + "serde", + "serde_json", + "tempfile", + "thiserror", + "tmc-langs-plugins", + "tmc-langs-util", + "url", + "walkdir", +] + [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-rustls" -version = "0.23.4" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -2403,9 +2529,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", @@ -2415,20 +2541,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", "toml_datetime", @@ -2454,9 +2580,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -2473,7 +2599,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cassowary", "crossterm 0.25.0", "unicode-segmentation", @@ -2512,9 +2638,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "22049a19f4a68748a168c0fc439f9516686aa045927ff767eca0a85101fb6e73" [[package]] name = "unicode-normalization" @@ -2551,12 +2677,12 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", - "idna", + "idna 0.4.0", "percent-encoding", "serde", ] @@ -2567,6 +2693,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d023da39d1fde5a8a3fe1f3e01ca9632ada0a63e9797de55a879d6e2236277be" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "version_check" version = "0.9.4" @@ -2594,11 +2730,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -2616,9 +2751,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2626,24 +2761,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.23", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -2653,9 +2788,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2663,28 +2798,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.23", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -2746,22 +2881,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" 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", + "windows-targets 0.48.1", ] [[package]] @@ -2779,7 +2899,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.1", ] [[package]] @@ -2799,9 +2919,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm 0.48.0", "windows_aarch64_msvc 0.48.0", @@ -2898,9 +3018,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.1" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" dependencies = [ "memchr", ] @@ -2925,15 +3045,15 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.4" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" +checksum = "5a56c84a8ccd4258aed21c92f70c0f6dea75356b6892ae27c24139da456f9336" [[package]] name = "zip" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0445d0fbc924bb93539b4316c11afb121ea39296f99a3c4c9edad09e3658cdef" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ "aes", "byteorder", @@ -2945,7 +3065,7 @@ dependencies = [ "hmac", "pbkdf2", "sha1", - "time 0.3.20", + "time 0.3.22", "zstd 0.11.2+zstd.1.5.2", ] diff --git a/Cargo.toml b/Cargo.toml index c943618..c8c5f4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,20 +2,21 @@ name = "tmc" version = "1.1.2" authors = [ - "University of Helsinki ", - "HoolaBoola ", - "Robustic ", - "ShootingStar91 ", - "Nooblue ", - "Daniel Martinez ", + "University of Helsinki ", + "HoolaBoola ", + "Robustic ", + "ShootingStar91 ", + "Nooblue ", + "Daniel Martinez ", ] edition = "2021" -description = "Client for downloading, testing and submitting exercises through the TestMyCode system." +description = "Client for downloading, testing and submitting exercises through the TestMyCode and MOOC.fi systems." license = "Apache-2.0" -rust-version = "1.66.1" +rust-version = "1.70.0" [dependencies] anyhow = { version = "1.0.56", features = ["backtrace"] } +bytes = "1.4.0" clap = { version = "4.0.7", features = ["derive"] } clap_complete = "4.0.2" crossterm = "0.26.0" @@ -23,20 +24,21 @@ flexi_logger = "0.25.3" indicatif = "0.17.1" log = "0.4.17" reqwest = { version = "0.11.9", default-features = false, features = [ - "blocking", - "json", - "rustls-tls", - "multipart", + "blocking", + "json", + "rustls-tls", + "multipart", ] } rpassword = "7.0.0" serde = "1.0.136" serde_json = "1.0.79" termcolor = "1.1.3" terminal_size = "0.2.1" -tmc-langs = { git = "https://github.com/rage/tmc-langs-rust/", ref = "0.31.2" } +tmc-langs = { git = "https://github.com/rage/tmc-langs-rust/", tag = "0.31.2" } toml = "0.7.2" tui = { version = "0.19.0", default-features = false, features = ['crossterm'] } url = "2.2.2" +uuid = { version = "1.4.0", features = ["v4"] } [dev-dependencies] assert_cmd = "2.0.4" @@ -45,3 +47,6 @@ predicates = "3.0.3" [build-dependencies] clap = { version = "4.0.7", features = ["derive"] } clap_complete = "4.0.2" + +[patch."https://github.com/rage/tmc-langs-rust/"] +tmc-langs = { path = "../tmc-langs-rust/crates/tmc-langs" } diff --git a/rustfmt.toml b/rustfmt.toml index a62b094..84bffc9 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,2 +1,2 @@ -imports_granularity="Crate" -group_imports="One" +group_imports = "One" +imports_granularity = "Crate" diff --git a/src/cli.rs b/src/cli.rs index 115b502..5a5bbe9 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,5 @@ use clap::{Parser, Subcommand, ValueEnum}; +use std::path::PathBuf; #[derive(Parser, Debug)] #[command( @@ -10,21 +11,24 @@ use clap::{Parser, Subcommand, ValueEnum}; arg_required_else_help(true) )] pub struct Cli { + #[command(subcommand)] + pub subcommand: Command, + /// Disable auto-update temporarily. #[arg(short = 'd', long, hide = !cfg!(windows))] pub no_update: bool, /// Force auto-update to run. #[arg(short = 'u', long, hide = !cfg!(windows))] pub force_update: bool, - /// Only for internal testing, disables server connection + + /// Only for internal testing, disables server connection. #[arg(long, hide = true)] pub testmode: bool, - #[command(subcommand)] - pub subcommand: Command, } #[derive(Subcommand, Debug)] pub enum Command { + // tmc commands /// List the available courses. Courses, /// Download exercises for a course. @@ -41,26 +45,56 @@ pub enum Command { /// If set, the exercises of this course are listed. If not set, the selection is done from an interactive menu. course: Option, }, - /// Login to TMC server + /// Login to TMC server. Login { /// Initiates the non-interactive mode. #[arg(short, long)] non_interactive: bool, }, - /// Logout from TMC server + /// Logout from TMC server. Logout, - /// Change organization + /// Change organization. Organization { /// Initiates the non-interactive mode. #[arg(short, long)] non_interactive: bool, }, - /// Submit exercise to TMC pastebin + /// Submit exercise to TMC pastebin. Paste { exercise: Option }, - /// Submit exercises to TMC server + /// Submit exercises to TMC server. Submit { exercise: Option }, - /// Run local exercise tests + /// Run local exercise tests. Test { exercise: Option }, + /// Updates course exercises. + Update { + /// If set, exercises in the current working directory are updated. + #[arg(short = 'd', long)] + currentdir: bool, + }, + + // MOOC commands + /// Currently enrolled courses.mooc.fi courses. + MoocCourses, + /// Active exercises of the selected course. + MoocCourseExercises { + /// If set, the exercises of this course are listed. If not set, the selection is done from an interactive menu. + course: Option, + }, + /// Downloads active exercises for the selected course. + MoocDownloadExercises { + /// If set, the exercises of this course are downloaded. If not set, the selection is done from an interactive menu. + course: Option, + /// If set, exercises are downloaded to the current working directory. + #[arg(short = 'd', long)] + currentdir: bool, + }, + /// Submits an exercise. + MoocSubmitExercise { + /// If set, the exercise at this path is submitted. If not set, the selection is done from an interactive menu. + path: Option, + }, + + // hidden commands /// Finishes the autoupdater. Administator rights needed. #[clap(hide = true)] Fetchupdate, @@ -73,12 +107,6 @@ pub enum Command { /// updates course from the tempfile. Administator rights needed. #[clap(hide = true)] Elevatedupdate, - /// Updates course exercises - Update { - /// If set, exercises in the current working directory are updated. - #[arg(short = 'd', long)] - currentdir: bool, - }, /// Generate completion scripts for command line usage. #[clap( hide = true, @@ -88,6 +116,12 @@ pub enum Command { GenerateCompletions { shell: ShellArg }, } +impl Command { + pub fn requires_organization_set(&self) -> bool { + matches!(self, Command::Download { .. } | Command::Courses { .. }) + } +} + #[derive(Debug, Clone, Copy, ValueEnum)] pub enum ShellArg { Bash, diff --git a/src/commands.rs b/src/commands.rs index b0f2195..e93f373 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -4,6 +4,7 @@ mod exercises; mod generate_completions; mod login; mod logout; +mod mooc; mod organization; mod paste; mod submit; @@ -37,11 +38,12 @@ pub fn handle(cli: Cli, io: &mut dyn Io) -> anyhow::Result<()> { }; // Check that organization is set - if let Command::Download { .. } | Command::Courses { .. } = cli.subcommand { + if cli.subcommand.requires_organization_set() { util::get_organization().context("No organization found. Run 'tmc organization' first.")?; } match cli.subcommand { + // tmc commands Command::Login { non_interactive } => { let interactive_mode = !non_interactive; login::login(io, &mut client, interactive_mode)?; @@ -70,6 +72,20 @@ pub fn handle(cli: Cli, io: &mut dyn Io) -> anyhow::Result<()> { paste::paste(io, &mut client, exercise.as_deref())?; } Command::Logout => logout::logout(io, &mut client)?, + + // mooc commands + Command::MoocCourses => mooc::courses::run(io, &mut client)?, + Command::MoocCourseExercises { course } => { + mooc::course_exercises::run(io, &mut client, course.as_deref())? + } + Command::MoocDownloadExercises { course, currentdir } => { + mooc::download_exercises::run(io, &mut client, course.as_deref(), currentdir)? + } + Command::MoocSubmitExercise { path } => { + mooc::submit_exercise::run(io, &mut client, path.as_deref())? + } + + // hidden commands Command::Fetchupdate => { #[cfg(target_os = "windows")] crate::updater::process_update()?; diff --git a/src/commands/courses.rs b/src/commands/courses.rs index 0bbec7b..8d0a800 100644 --- a/src/commands/courses.rs +++ b/src/commands/courses.rs @@ -18,9 +18,14 @@ mod tests { use reqwest::Url; use std::{path::Path, slice::Iter}; use tmc_langs::{ - ClientError, Course, CourseDetails, CourseExercise, DownloadOrUpdateCourseExercisesResult, - DownloadResult, ExercisesDetails, LangsError, Language, NewSubmission, Organization, - SubmissionFinished, SubmissionStatus, + tmc::{ + response::{ + Course, CourseDetails, CourseExercise, ExercisesDetails, NewSubmission, + Organization, SubmissionFinished, SubmissionStatus, + }, + TestMyCodeClientError, + }, + DownloadOrUpdateCourseExercisesResult, DownloadResult, LangsError, Language, }; pub struct IoTest<'a> { list: &'a mut Vec, @@ -129,7 +134,7 @@ mod tests { fn wait_for_submission( &self, _submission_url: Url, - ) -> Result { + ) -> Result { Ok(SubmissionFinished { api_version: 0, all_tests_passed: Some(true), @@ -163,7 +168,7 @@ mod tests { fn get_exercise_details( &mut self, _exercise_ids: Vec, - ) -> Result, ClientError> { + ) -> Result, TestMyCodeClientError> { unimplemented!() } @@ -178,10 +183,16 @@ mod tests { }) } - fn get_course_details(&self, _: u32) -> std::result::Result { + fn get_course_details( + &self, + _: u32, + ) -> std::result::Result { unimplemented!() } - fn get_organization(&self, _: &str) -> std::result::Result { + fn get_organization( + &self, + _: &str, + ) -> std::result::Result { unimplemented!() } } diff --git a/src/commands/download.rs b/src/commands/download.rs index 1c1566d..c04b340 100644 --- a/src/commands/download.rs +++ b/src/commands/download.rs @@ -9,7 +9,10 @@ use crate::{ }; use anyhow::Context; use std::{path::Path, process::Command}; -use tmc_langs::{ClientUpdateData, Course, DownloadResult}; +use tmc_langs::{ + tmc::{response::Course, ClientUpdateData}, + DownloadResult, +}; // Downloads course exercises // course_name as None will trigger interactive menu for selecting a course diff --git a/src/commands/exercises.rs b/src/commands/exercises.rs index b647550..dd680ad 100644 --- a/src/commands/exercises.rs +++ b/src/commands/exercises.rs @@ -1,6 +1,6 @@ use super::util::{self, choose_course, Client}; use crate::io::{Io, PrintColor}; -use tmc_langs::CourseExercise; +use tmc_langs::tmc::response::CourseExercise; /// Lists exercises for a given course pub fn list_exercises( @@ -97,9 +97,14 @@ mod tests { use reqwest::Url; use std::{path::Path, slice::Iter}; use tmc_langs::{ - ClientError, Course, CourseDetails, CourseExercise, DownloadOrUpdateCourseExercisesResult, - DownloadResult, ExercisesDetails, LangsError, Language, NewSubmission, Organization, - SubmissionFinished, SubmissionStatus, + tmc::{ + response::{ + Course, CourseDetails, CourseExercise, ExercisesDetails, NewSubmission, + Organization, SubmissionFinished, SubmissionStatus, + }, + TestMyCodeClientError, + }, + DownloadOrUpdateCourseExercisesResult, DownloadResult, LangsError, Language, }; pub struct IoTest<'a> { @@ -203,7 +208,7 @@ mod tests { fn wait_for_submission( &self, _submission_url: Url, - ) -> Result { + ) -> Result { Ok(SubmissionFinished { api_version: 0, all_tests_passed: Some(true), @@ -305,7 +310,7 @@ mod tests { fn get_exercise_details( &mut self, _exercise_ids: Vec, - ) -> Result, ClientError> { + ) -> Result, TestMyCodeClientError> { unimplemented!() } fn update_exercises( @@ -325,10 +330,10 @@ mod tests { }) } - fn get_course_details(&self, _: u32) -> Result { + fn get_course_details(&self, _: u32) -> Result { unimplemented!() } - fn get_organization(&self, _: &str) -> Result { + fn get_organization(&self, _: &str) -> Result { unimplemented!() } } diff --git a/src/commands/login.rs b/src/commands/login.rs index 6ffefd5..19131cf 100644 --- a/src/commands/login.rs +++ b/src/commands/login.rs @@ -1,11 +1,11 @@ -use super::{download, organization, util, util::Client}; +use super::{download, util, util::Client}; use crate::io::{Io, PrintColor}; use anyhow::Context; pub fn login( io: &mut dyn Io, client: &mut dyn Client, - interactive_mode: bool, + _interactive_mode: bool, ) -> anyhow::Result<()> { io.print("Email / username: ", PrintColor::Normal)?; let mut username = io.read_line()?; @@ -29,26 +29,36 @@ pub fn login( let message = client.try_login(username, password)?; io.println(&message, PrintColor::Success)?; + /* + now that courses mooc is supported, + no need to always select an org if interactive_mode { organization::set_organization(io, client) } else { organization::set_organization_old(io, client) } .context("Could not set organization")?; + */ if client.is_test_mode() { return Ok(()); } + /* + now that courses mooc is supported, + no need to always select a course if interactive_mode { download_after_login(client, io)?; } else { - io.println("Logged in and selected organization", PrintColor::Success)?; + } + */ + + io.println("Logged in", PrintColor::Success)?; Ok(()) } -pub fn download_after_login(client: &mut dyn Client, io: &mut dyn Io) -> anyhow::Result<()> { +pub fn _download_after_login(client: &mut dyn Client, io: &mut dyn Io) -> anyhow::Result<()> { io.println("Fetching courses...", PrintColor::Normal)?; let courses = client.list_courses()?; diff --git a/src/commands/mooc.rs b/src/commands/mooc.rs new file mode 100644 index 0000000..1b9d186 --- /dev/null +++ b/src/commands/mooc.rs @@ -0,0 +1,63 @@ +use super::util::Client; +use crate::{Io, PrintColor}; +use anyhow::Context; +use std::collections::HashMap; +use tmc_langs::mooc::CourseInstance; + +pub mod course_exercises; +pub mod courses; +pub mod download_exercises; +pub mod submit_exercise; + +// Ok(Some(course)) => found course by slug or selection +// Ok(None) => user declined to select a course +// Err => something went wrong +fn get_course_by_slug_or_selection( + io: &mut dyn Io, + client: &mut dyn Client, + slug: Option<&str>, +) -> anyhow::Result> { + let courses = client.mooc_courses()?; + let course = if let Some(slug) = slug { + + courses + .into_iter() + .find(|c| c.course_slug == slug) + .with_context(|| format!("Failed to find course with the given slug '{slug}'"))? + } else { + let mut course_name_to_course = courses + .into_iter() + .map(|c| { + let key = self::course_identifier(&c); + (key, c) + }) + .collect::>(); + let keys = course_name_to_course + .keys() + .map(String::as_str) + .collect::>(); + + match crate::interactive::interactive_list("Select course:", &keys)? { + Some(selection) => course_name_to_course + .remove(&selection) + .expect("Invalid selection"), + None => { + io.print("Did not select a course", PrintColor::Normal)?; + return Ok(None); + } + } + }; + + Ok(Some(course)) +} + +fn course_identifier(course: &CourseInstance) -> String { + let instance_name = course + .instance_name + .as_deref() + .unwrap_or("default instance"); + format!( + "{} ({} | {})", + course.course_name, course.course_slug, instance_name + ) +} diff --git a/src/commands/mooc/course_exercises.rs b/src/commands/mooc/course_exercises.rs new file mode 100644 index 0000000..b4938ec --- /dev/null +++ b/src/commands/mooc/course_exercises.rs @@ -0,0 +1,34 @@ +use super::super::util::Client; +use crate::{Io, PrintColor}; +use tmc_langs::mooc::{CourseInstance, TmcExerciseSlide}; + +pub fn run(io: &mut dyn Io, client: &mut dyn Client, slug: Option<&str>) -> anyhow::Result<()> { + let Some(course) = super::get_course_by_slug_or_selection(io, client, slug)? else { + return Ok(()); + }; + + let mut exercises = client.mooc_course_exercises(course.id)?; + exercises.sort_by_key(|e| e.exercise_order_number); + print_exercises(io, &course, &exercises)?; + + Ok(()) +} + +/// Prints information about given exercises +fn print_exercises( + io: &mut dyn Io, + course: &CourseInstance, + exercises: &[TmcExerciseSlide], +) -> anyhow::Result<()> { + let course_identifier = super::course_identifier(course); + io.println( + &format!("\nActive exercises on {}", course_identifier), + PrintColor::Normal, + )?; + + for exercise in exercises { + io.println(&format!(" {}", exercise.exercise_name), PrintColor::Normal)?; + } + + Ok(()) +} diff --git a/src/commands/mooc/courses.rs b/src/commands/mooc/courses.rs new file mode 100644 index 0000000..151b3fc --- /dev/null +++ b/src/commands/mooc/courses.rs @@ -0,0 +1,25 @@ +use super::super::util::Client; +use crate::{Io, PrintColor}; +use tmc_langs::mooc::CourseInstance; + +pub fn run(io: &mut dyn Io, client: &mut dyn Client) -> anyhow::Result<()> { + let mut courses = client.mooc_courses()?; + courses.sort_by_cached_key(|c| c.course_name.clone()); + print_courses(io, &courses)?; + Ok(()) +} + +/// Prints information about given exercises +fn print_courses(io: &mut dyn Io, course: &[CourseInstance]) -> anyhow::Result<()> { + io.println( + "\nCurrently enrolled courses.mooc.fi courses", + PrintColor::Normal, + )?; + + for course in course { + let course_identifier = super::course_identifier(course); + io.println(&format!(" {}", course_identifier), PrintColor::Normal)?; + } + + Ok(()) +} diff --git a/src/commands/mooc/download_exercises.rs b/src/commands/mooc/download_exercises.rs new file mode 100644 index 0000000..1aad481 --- /dev/null +++ b/src/commands/mooc/download_exercises.rs @@ -0,0 +1,107 @@ +use super::super::util::Client; +use crate::{ + config::{LocalExercise, TmcCliConfig}, + Io, PrintColor, +}; +use std::{io::Cursor, path::Path}; +use tmc_langs::{ + mooc::{CourseInstance, PublicSpec, TmcExerciseSlide}, + Compression, +}; + +pub fn run( + io: &mut dyn Io, + client: &mut dyn Client, + slug: Option<&str>, + current_dir: bool, +) -> anyhow::Result<()> { + let Some(course) = super::get_course_by_slug_or_selection(io, client, slug)? else { + return Ok(()); + }; + + let dir = if current_dir { + std::env::current_dir()? + } else { + crate::commands::util::get_projects_dir()? + }; + + let exercises = client.mooc_course_exercises(course.id)?; + download_exercises(io, client, &course, &exercises, &dir)?; + + Ok(()) +} + +/// Prints information about given exercises +fn download_exercises( + io: &mut dyn Io, + client: &mut dyn Client, + course: &CourseInstance, + exercises: &[TmcExerciseSlide], + dir: &Path, +) -> anyhow::Result<()> { + io.println( + &format!( + "Downloading exercises for {} into {}...", + course.course_name, + dir.display() + ), + PrintColor::Normal, + )?; + let mut config = TmcCliConfig::load()?; + + for exercise in exercises { + for task in &exercise.tasks { + match &task.public_spec { + Some(PublicSpec::Editor { + archive_name: _, + archive_download_url, + }) => { + let bytes = client.mooc_download_exercise(archive_download_url.to_owned())?; + let dir_name = format!( + "{}-{}-{}", + exercise.exercise_order_number, exercise.exercise_name, task.order_number + ); + let target_location = dir.join(dir_name); + tmc_langs::extract_project( + Cursor::new(bytes.as_ref()), + &target_location, + Compression::TarZstd, + false, + false, + )?; + + io.println( + &format!( + "Downloaded '{}' to '{}'", + exercise.exercise_name, + target_location.display() + ), + PrintColor::Success, + )?; + config.add_exercise(LocalExercise { + exercise_id: exercise.exercise_id, + slide_id: exercise.slide_id, + task_id: task.task_id, + location: target_location, + }); + } + Some(PublicSpec::Browser { .. }) => { + io.println(&format!("Skipping exercise {} as it is meant to be completed in the course material", exercise.exercise_name), PrintColor::Normal)?; + } + None => { + io.println( + &format!( + "Skipping exercise {} as it is not active yet", + exercise.exercise_name + ), + PrintColor::Normal, + )?; + } + } + } + } + + config.save()?; + + Ok(()) +} diff --git a/src/commands/mooc/submit_exercise.rs b/src/commands/mooc/submit_exercise.rs new file mode 100644 index 0000000..feaa580 --- /dev/null +++ b/src/commands/mooc/submit_exercise.rs @@ -0,0 +1,26 @@ +use super::super::util::Client; +use crate::Io; +use std::path::{Path, PathBuf}; +use tmc_langs::mooc::{ExerciseSlideSubmission, ExerciseTaskSubmission}; +use uuid::Uuid; + +pub fn run(_io: &mut dyn Io, client: &mut dyn Client, path: Option<&Path>) -> anyhow::Result<()> { + let selected_path; + let _path = match path { + Some(path) => path, + None => { + selected_path = PathBuf::from("asd"); + &selected_path + } + }; + let exercise_id = Uuid::new_v4(); + let exercise_slide_submission = ExerciseSlideSubmission { + exercise_slide_id: Uuid::new_v4(), + exercise_task_submissions: vec![ExerciseTaskSubmission { + exercise_task_id: Uuid::new_v4(), + data_json: serde_json::Value::Null, + }], + }; + client.mooc_submit_exercise(exercise_id, &exercise_slide_submission)?; + Ok(()) +} diff --git a/src/commands/paste.rs b/src/commands/paste.rs index 0931378..93a97d3 100644 --- a/src/commands/paste.rs +++ b/src/commands/paste.rs @@ -5,7 +5,7 @@ use crate::{ progress_reporting::ProgressBarManager, }; use anyhow::Context; -use tmc_langs::{ClientUpdateData, Language}; +use tmc_langs::{tmc::ClientUpdateData, Language}; /// Sends the course exercise submission with paste message to the server. /// Path to the exercise can be given as a parameter or diff --git a/src/commands/submit.rs b/src/commands/submit.rs index 6aac323..bbf281d 100644 --- a/src/commands/submit.rs +++ b/src/commands/submit.rs @@ -6,7 +6,10 @@ use crate::{ }; use anyhow::{Context, Result}; use reqwest::Url; -use tmc_langs::{ClientUpdateData, Language, SubmissionFinished}; +use tmc_langs::{ + tmc::{response::SubmissionFinished, ClientUpdateData}, + Language, +}; /// Sends the course exercise submission to the server. /// Path to the exercise can be given as a parameter or diff --git a/src/commands/util.rs b/src/commands/util.rs index d3e7791..c63a192 100644 --- a/src/commands/util.rs +++ b/src/commands/util.rs @@ -1,18 +1,28 @@ use crate::{ + config::TmcCliConfig, interactive::{self, interactive_list}, io::{Io, PrintColor}, }; use anyhow::Context; +use bytes::Bytes; use reqwest::Url; use std::{ env, path::{Path, PathBuf}, }; use tmc_langs::{ - ClientError, ConfigValue, Course, CourseDetails, CourseExercise, Credentials, - DownloadOrUpdateCourseExercisesResult, DownloadResult, ExercisesDetails, LangsError, Language, - NewSubmission, Organization, ProjectsConfig, SubmissionFinished, TmcClient, TmcConfig, Token, + mooc::{self, ExerciseSlideSubmission, MoocClient}, + tmc::{ + response::{ + Course, CourseDetails, CourseExercise, ExercisesDetails, NewSubmission, Organization, + SubmissionFinished, + }, + TestMyCodeClient, TestMyCodeClientError, Token, + }, + Credentials, DownloadOrUpdateCourseExercisesResult, DownloadResult, LangsError, Language, + ProjectsConfig, }; +use uuid::Uuid; pub const PLUGIN: &str = "tmc_cli_rust"; pub const PLUGIN_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -20,17 +30,22 @@ pub const SUCCESSFUL_LOGIN: &str = "Logged in successfully!"; pub const WRONG_LOGIN: &str = "Wrong username or password"; pub struct ClientProduction { - pub tmc_client: TmcClient, + pub tmc_client: TestMyCodeClient, + pub mooc_client: MoocClient, pub test_mode: bool, } pub trait Client { + // tmc commands fn load_login(&mut self) -> anyhow::Result<()>; fn try_login(&mut self, username: String, password: String) -> anyhow::Result; fn list_courses(&mut self) -> anyhow::Result>; fn get_organizations(&mut self) -> anyhow::Result>; fn logout(&mut self) -> anyhow::Result<()>; - fn wait_for_submission(&self, submission_url: Url) -> Result; + fn wait_for_submission( + &self, + submission_url: Url, + ) -> Result; fn submit( &self, projects_dir: &Path, @@ -42,15 +57,18 @@ pub trait Client { fn get_exercise_details( &mut self, exercise_ids: Vec, - ) -> Result, ClientError>; + ) -> Result, TestMyCodeClientError>; fn download_or_update_exercises( &mut self, download_params: &[u32], path: &Path, ) -> Result; fn is_test_mode(&mut self) -> bool; - fn get_course_details(&self, course_id: u32) -> Result; - fn get_organization(&self, organization_slug: &str) -> Result; + fn get_course_details(&self, course_id: u32) -> Result; + fn get_organization( + &self, + organization_slug: &str, + ) -> Result; fn update_exercises( &mut self, path: &Path, @@ -63,18 +81,51 @@ pub trait Client { paste_message: Option, locale: Option, ) -> Result; + + // mooc commands + fn mooc_courses(&self) -> anyhow::Result> { + todo!() + } + fn mooc_course_exercises( + &self, + _course_instance_id: Uuid, + ) -> anyhow::Result> { + todo!() + } + fn mooc_download_exercise(&self, _url: String) -> anyhow::Result { + todo!() + } + fn mooc_submit_exercise( + &self, + _exercise_id: Uuid, + _exercise_slide_submission: &ExerciseSlideSubmission, + ) -> anyhow::Result<()> { + todo!() + } } impl ClientProduction { pub fn new(test_mode: bool) -> anyhow::Result { - let (tmc_client, _credentials) = tmc_langs::init_tmc_client_with_credentials( - Url::parse("https://tmc.mooc.fi").expect("Server address should always be correct."), + let tmc_root_url_env = env::var("TMC_LANGS_TMC_ROOT_URL"); + let tmc_root_url = tmc_root_url_env.as_deref().unwrap_or("https://tmc.mooc.fi"); + let tmc_root_url = tmc_root_url + .parse() + .with_context(|| format!("Failed to parse URL {tmc_root_url}"))?; + + let mooc_root_url = env::var("TMC_LANGS_MOOC_ROOT_URL") + .unwrap_or_else(|_| "https://courses.mooc.fi".to_string()); + + let (tmc_client, _credentials) = tmc_langs::init_testmycode_client_with_credentials( + tmc_root_url, PLUGIN, PLUGIN_VERSION, )?; + let (mooc_client, _credentials) = + tmc_langs::init_mooc_client_with_credentials(mooc_root_url, PLUGIN)?; Ok(ClientProduction { tmc_client, + mooc_client, test_mode, }) } @@ -103,6 +154,7 @@ impl ClientProduction { } impl Client for ClientProduction { + // tmc commands fn paste( &self, projects_dir: &Path, @@ -123,11 +175,11 @@ impl Client for ClientProduction { locale, ) { Err(client_error) => match client_error { - LangsError::TmcClient(ClientError::HttpError { status, error, .. }) => { + LangsError::TestMyCodeClient(TestMyCodeClientError::HttpError { status, error, .. }) => { Err(format!("Status {status}, message: {error}")) } _ => Err( - "Received unhandled ClientError when calling paste command from tmc_client" + "Received unhandled TestMyCodeClientError when calling paste command from tmc_client" .to_string(), ), }, @@ -142,13 +194,11 @@ impl Client for ClientProduction { fn load_login(&mut self) -> anyhow::Result<()> { if self.test_mode { // Test login exists if config-file has key-value pair test_login = "test_logged_in" - let config = TmcConfig::load(PLUGIN, &get_path()?)?; - let test_login_exists = match config.get("test_login") { - ConfigValue::Value(Some(value)) => { - toml::Value::as_str(&value).context("invalid value")? == "test_logged_in" - } - _ => false, - }; + let config = TmcCliConfig::load()?; + let test_login_exists = config + .get_test_login() + .map(|tl| tl == "test_logged_in") + .unwrap_or_default(); if test_login_exists { return Ok(()); } else { @@ -167,16 +217,11 @@ impl Client for ClientProduction { fn try_login(&mut self, username: String, password: String) -> anyhow::Result { if self.test_mode { if username == "testusername" && password == "testpassword" { - let mut config = TmcConfig::load(PLUGIN, &get_path()?)?; + let mut config = TmcCliConfig::load()?; - if let Err(_err) = config.insert( - "test_login".to_string(), - toml::Value::String("test_logged_in".to_string()), - ) { - anyhow::bail!("Test login value could not be changed in config file"); - } + config.insert_test_login(); - if let Err(_err) = config.save(&get_path()?) { + if let Err(_err) = config.save() { anyhow::bail!("Problem saving login"); } @@ -242,7 +287,7 @@ impl Client for ClientProduction { } Ok(course_list) } - Err(ClientError::NotAuthenticated) => { + Err(TestMyCodeClientError::NotAuthenticated) => { anyhow::bail!("Login token is invalid. Please try logging in again.") } Err(err) => anyhow::bail!("Unexpected error: '{err}'."), @@ -280,13 +325,10 @@ impl Client for ClientProduction { fn logout(&mut self) -> anyhow::Result<()> { if self.test_mode { // Remove test login from config file - let mut config = - TmcConfig::load(PLUGIN, &get_path()?).context("Could not load the config")?; - config - .remove("test_login") - .context("Could not remove test login from config in test mode")?; + let mut config = TmcCliConfig::load().context("Could not load the config")?; + config.remove_test_login(); config - .save(&get_path()?) + .save() .context("Could not save config after removing test login in test mode")?; return Ok(()); } @@ -296,7 +338,10 @@ impl Client for ClientProduction { Ok(()) } - fn wait_for_submission(&self, submission_url: Url) -> Result { + fn wait_for_submission( + &self, + submission_url: Url, + ) -> Result { self.tmc_client.wait_for_submission_at(submission_url) } fn update_exercises( @@ -354,7 +399,7 @@ impl Client for ClientProduction { } match self.tmc_client.get_course_exercises(course_id) { Ok(exercises) => Ok(exercises), - Err(ClientError::NotAuthenticated) => { + Err(TestMyCodeClientError::NotAuthenticated) => { anyhow::bail!("Login token is invalid. Please try logging in again.") } Err(err) => anyhow::bail!("Unexpected error: '{err}'."), @@ -364,7 +409,7 @@ impl Client for ClientProduction { fn get_exercise_details( &mut self, exercise_ids: Vec, - ) -> Result, ClientError> { + ) -> Result, TestMyCodeClientError> { if self.test_mode { return Ok(vec![ExercisesDetails { id: 0, @@ -392,7 +437,7 @@ impl Client for ClientProduction { tmc_langs::download_or_update_course_exercises(&self.tmc_client, path, exercise_ids, true) } - fn get_course_details(&self, course_id: u32) -> Result { + fn get_course_details(&self, course_id: u32) -> Result { if self.test_mode { let course = Course { id: 0, @@ -414,7 +459,10 @@ impl Client for ClientProduction { self.tmc_client.get_course_details(course_id) } } - fn get_organization(&self, organization_slug: &str) -> Result { + fn get_organization( + &self, + organization_slug: &str, + ) -> Result { if self.test_mode { return Ok(Organization { name: "String".to_string(), @@ -426,6 +474,34 @@ impl Client for ClientProduction { } self.tmc_client.get_organization(organization_slug) } + + // mooc commands + fn mooc_courses(&self) -> anyhow::Result> { + let courses = self.mooc_client.course_instances()?; + Ok(courses) + } + fn mooc_course_exercises( + &self, + course_instance_id: Uuid, + ) -> anyhow::Result> { + let exercises = self + .mooc_client + .course_instance_exercise_slides(course_instance_id)?; + Ok(exercises) + } + fn mooc_download_exercise(&self, url: String) -> anyhow::Result { + let bytes = self.mooc_client.download(url)?; + Ok(bytes) + } + fn mooc_submit_exercise( + &self, + exercise_id: Uuid, + exercise_slide_submission: &ExerciseSlideSubmission, + ) -> anyhow::Result<()> { + self.mooc_client + .submit(exercise_id, exercise_slide_submission)?; + Ok(()) + } } pub fn get_credentials() -> Option { @@ -434,31 +510,24 @@ pub fn get_credentials() -> Option { } // Returns slug of organization as String (if successful) -#[allow(dead_code)] pub fn get_organization() -> anyhow::Result { - let config = TmcConfig::load(PLUGIN, &get_path()?)?; + let config = TmcCliConfig::load()?; // convert the toml::Value to String (if possible) - match config.get("organization") { - ConfigValue::Value(Some(value)) => Ok(toml::Value::as_str(&value) - .context("invalid value")? - .to_string()), - _ => anyhow::bail!("missing value"), + match config.get_organization() { + Some(org) => Ok(org.to_string()), + _ => anyhow::bail!("No organization set"), } } pub fn set_organization(org: String) -> anyhow::Result<()> { - let mut config = match TmcConfig::load(PLUGIN, &get_path()?) { + let mut config = match TmcCliConfig::load() { Ok(config) => config, _ => anyhow::bail!("Config could not be loaded"), }; - config - .insert("organization".to_string(), toml::Value::String(org)) - .context("Organization could not be changed")?; + config.insert_organization(org); - config - .save(&get_path()?) - .context("Problem saving configurations")?; + config.save().context("Problem saving configurations")?; Ok(()) } @@ -509,10 +578,6 @@ pub fn exercise_pathfinder(path: Option<&str>) -> anyhow::Result { } } -pub fn get_path() -> anyhow::Result { - TmcConfig::get_location(PLUGIN).map_err(Into::into) -} - pub fn get_projects_dir() -> anyhow::Result { tmc_langs::get_projects_dir(PLUGIN).map_err(Into::into) } diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..cb87b17 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,69 @@ +//! Wrapper around TmcConfig + +use crate::commands::util; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use tmc_langs::TmcConfig; +use toml::Value; +use uuid::Uuid; + +pub struct TmcCliConfig { + config: TmcConfig, + added_exercises: Vec, +} + +impl TmcCliConfig { + pub fn load() -> anyhow::Result { + let config = TmcConfig::load(util::PLUGIN)?; + Ok(Self { + config, + added_exercises: Vec::new(), + }) + } + + pub fn save(self) -> anyhow::Result<()> { + let Self { + mut config, + added_exercises, + } = self; + config.insert("exercises".to_string(), Value::try_from(added_exercises)?); + config.save()?; + Ok(()) + } + + pub fn get_organization(&self) -> Option<&str> { + self.config.get("organization").and_then(|v| v.as_str()) + } + + pub fn insert_organization(&mut self, org: String) { + self.config + .insert("organization".to_string(), toml::Value::String(org)); + } + + pub fn get_test_login(&self) -> Option<&str> { + self.config.get("test_login").and_then(|v| v.as_str()) + } + + pub fn insert_test_login(&mut self) { + let key = "test_login".to_string(); + let value = toml::Value::String("test_logged_in".to_string()); + self.config.insert(key, value); + } + + pub fn remove_test_login(&mut self) { + let key = "test_login"; + self.config.remove(key); + } + + pub fn add_exercise(&mut self, exercise: LocalExercise) { + self.added_exercises.push(exercise); + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct LocalExercise { + pub exercise_id: Uuid, + pub slide_id: Uuid, + pub task_id: Uuid, + pub location: PathBuf, +} diff --git a/src/lib.rs b/src/lib.rs index 39a995b..021fdd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod cli; mod commands; +mod config; mod interactive; mod io; mod progress_reporting; diff --git a/src/updater.rs b/src/updater.rs index 4fd24a2..0f6591e 100644 --- a/src/updater.rs +++ b/src/updater.rs @@ -105,7 +105,7 @@ fn elevate(command: String) -> anyhow::Result<()> { } fn is_it_time_yet() -> anyhow::Result { - let config = TmcConfig::load(PLUGIN, get_path()?.as_path())?; + let config = TmcCliConfig::load()?; let value = config.get("update-last-checked"); let last_check = match &value { @@ -129,7 +129,7 @@ fn is_it_time_yet() -> anyhow::Result { } fn generate_time_stamp() -> anyhow::Result<()> { - let mut config = TmcConfig::load(PLUGIN, get_path()?.as_path())?; + let mut config = TmcCliConfig::load()?; let now = SystemTime::now(); let since_the_epoch = now .duration_since(UNIX_EPOCH) diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 0000000..1a7baeb --- /dev/null +++ b/taplo.toml @@ -0,0 +1,13 @@ +# Configuration file for https://crates.io/crates/taplo-cli +# Format toml files with `taplo fmt` + +[formatting] +align_comments = false +reorder_keys = true + +[[rule]] +include = ["**/Cargo.toml"] +keys = ["package"] + +[rule.formatting] +reorder_keys = false