From 8159a465e238707af9d4bc664622a0f56a80af3f Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Mon, 1 Jan 2024 18:23:22 +0800 Subject: [PATCH 01/10] 2024 Happy New Year! Update toolchain version to 2024-01-01 and update github ci config. --- .github/actions/build/action.yml | 2 +- .github/workflows/build-dev.yml | 7 +--- .github/workflows/build-release.yml | 10 +---- rust-fmt.toml | 5 +++ rust-toolchain.toml | 5 ++- src/main.rs | 58 ++++++++++++++++++----------- 6 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 rust-fmt.toml diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 08a7b37..91c3279 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -18,4 +18,4 @@ runs: - name: Build release if: ${{ inputs.release == 'true' }} shell: bash - run: cargo build --target ${{ inputs.target }} -r + run: cargo build --release --target ${{ inputs.target }} -r diff --git a/.github/workflows/build-dev.yml b/.github/workflows/build-dev.yml index a517808..0390cdf 100644 --- a/.github/workflows/build-dev.yml +++ b/.github/workflows/build-dev.yml @@ -39,12 +39,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Setup Rust toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - override: true - toolchain: nightly-2023-09-06 - components: rustfmt, clippy + uses: dsherret/rust-toolchain-file@v1 - name: Show Rust toolchain version shell: bash diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 976d5ef..be887ef 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -30,15 +30,10 @@ jobs: - name: Checkout uses: actions/checkout@v3 with: - ref: ${{ github.event.pull_request.head.sha }} + ref: ${{ github.ref }} # github.ref 变量将自动填充为触发事件的分支或标签名 - name: Setup Rust toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - override: true - toolchain: nightly-2023-09-06 - components: rustfmt, clippy + uses: dsherret/rust-toolchain-file@v1 - name: Setup musl-tools if: matrix.targets.target == 'x86_64-unknown-linux-musl' @@ -99,4 +94,3 @@ jobs: uses: softprops/action-gh-release@v1 with: files: ${{ steps.gen-name.outputs.NAME }}.zip - diff --git a/rust-fmt.toml b/rust-fmt.toml new file mode 100644 index 0000000..9829022 --- /dev/null +++ b/rust-fmt.toml @@ -0,0 +1,5 @@ +max_width = 79 # 设置最大行宽为 100 个字符 +tab_spaces = 4 # 设置缩进宽度为 4 个空格 +edition = "2021" # 设置 Rust 版本(根据实际项目版本进行调整) +use_small_heuristics = "Max" # 设置换行策略 +newline_style = "Auto" # 设置换行符风格,根据平台自动选择 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index fac5529..5b6bd4a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] -profile = "default" -channel = "nightly-2023-12-27" +profile = "minimal" +channel = "nightly-2024-01-01" +components = [ "rustfmt", "clippy" ] diff --git a/src/main.rs b/src/main.rs index 7b361dc..5ba6d2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ #![feature(try_blocks)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(type_name_of_val)] #![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![warn(clippy::all, clippy::nursery, clippy::cargo_common_metadata)] @@ -45,6 +44,7 @@ fn show_non_printable_chars(text: String) -> String { .replace("\r\n", &make_red("␍␊\r\n")) } +#[allow(clippy::missing_const_for_fn)] fn panic_if_err(result: &Result) { if let Err(e) = result { panic!("{}", e) @@ -87,19 +87,23 @@ async fn main() -> Result<()> { display::user_info(style, &user_info)? } _ if let Some((skip, take, r#type, align)) = parser::ing::list_ing(&args) => { - let ing_with_comment_iter = infer::>(try { - let ing_api = Ing::new(pat?); - let ing_vec = ing_api.get_list(skip, take, &r#type).await?; - ing_vec.into_iter() - .map(|ing| async { - let result = ing_api.get_comment_list(ing.id).await; - result.map(|comment_vec| (ing, comment_vec)) - }) - .join_all() - .await - .into_iter() - .collect::>>()? - }).map(|vec| vec.into_iter().dyn_rev(rev)); + let ing_with_comment_iter = infer::>( + try { + let ing_api = Ing::new(pat?); + let ing_vec = ing_api.get_list(skip, take, &r#type).await?; + ing_vec + .into_iter() + .map(|ing| async { + let result = ing_api.get_comment_list(ing.id).await; + result.map(|comment_vec| (ing, comment_vec)) + }) + .join_all() + .await + .into_iter() + .collect::>>()? + }, + ) + .map(|vec| vec.into_iter().dyn_rev(rev)); foe.then(|| panic_if_err(&ing_with_comment_iter)); display::list_ing(style, time_style, ing_with_comment_iter, align)? } @@ -113,7 +117,9 @@ async fn main() -> Result<()> { } _ if let Some((content, id)) = parser::ing::comment_ing(&args) => { let content = try { - Ing::new(pat?).comment(id, content.clone(), None, None).await?; + Ing::new(pat?) + .comment(id, content.clone(), None, None) + .await?; content }; foe.then(|| panic_if_err(&content)); @@ -131,7 +137,8 @@ async fn main() -> Result<()> { } _ if let Some(id) = parser::post::show_post_comment(&args) => { let comment_iter = Post::new(pat?) - .get_comment_list(id).await + .get_comment_list(id) + .await .map(|vec| vec.into_iter().dyn_rev(rev)); foe.then(|| panic_if_err(&comment_iter)); display::show_post_comment(style, time_style, comment_iter)? @@ -164,18 +171,26 @@ async fn main() -> Result<()> { let result = Post::new(pat?) .search_site(skip, take, kw) .await - .map(|vec | vec.into_iter().dyn_rev(rev)); + .map(|vec| vec.into_iter().dyn_rev(rev)); foe.then(|| panic_if_err(&result)); display::search_site_post(style, time_style, result)? } _ if let Some(create_cmd) = parser::post::create_post(&args) => { - let CreateCmd { title, body, publish } = create_cmd; + let CreateCmd { + title, + body, + publish, + } = create_cmd; let id = Post::new(pat?).create(title, body, *publish).await; foe.then(|| panic_if_err(&id)); display::create_post(style, &id) } _ if let Some((id, update_cmd)) = parser::post::update_post(&args) => { - let UpdateCmd { title, body, publish } = update_cmd; + let UpdateCmd { + title, + body, + publish, + } = update_cmd; let id = Post::new(pat?).update(id, title, body, publish).await; foe.then(|| panic_if_err(&id)); display::update_post(style, &id) @@ -197,9 +212,8 @@ async fn main() -> Result<()> { display::list_fav(style, time_style, fav_iter)? } - _ if no_operation(&args) => - infer::(Args::command()).render_help().to_string(), - _ => "Invalid usage, follow '--help' for more information".to_owned() + _ if no_operation(&args) => infer::(Args::command()).render_help().to_string(), + _ => "Invalid usage, follow '--help' for more information".to_owned(), }; if global_opt.quiet { From aaf1792e81d942802298c646d351667feb452dcb Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Mon, 1 Jan 2024 23:54:39 +0800 Subject: [PATCH 02/10] Design the Cli API, move execute file to bin dir, change to lib --- Cargo.lock | 2 +- Cargo.toml | 6 +- src/main.rs | 241 ---------------------------------------------------- 3 files changed, 6 insertions(+), 243 deletions(-) delete mode 100644 src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 7fc3726..dd007c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,7 +227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] -name = "cnb" +name = "cnblogs_lib" version = "0.0.0-dev" dependencies = [ "anyhow", diff --git a/Cargo.toml b/Cargo.toml index edffc32..481b8a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cnb" +name = "cnblogs_lib" # WRN: Version will be updated by CI while create a tag, NERVER change this. version = "0.0.0-dev" edition = "2021" @@ -47,3 +47,7 @@ colored = "2.0.4" terminal_size = "0.2.6" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bin]] +name = "cnb" +path = "src/bin/cnb.rs" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 5ba6d2d..0000000 --- a/src/main.rs +++ /dev/null @@ -1,241 +0,0 @@ -#![feature(try_blocks)] -#![feature(if_let_guard)] -#![feature(let_chains)] -#![feature(iterator_try_collect)] -#![feature(iterator_try_reduce)] -#![warn(clippy::all, clippy::nursery, clippy::cargo_common_metadata)] - -use crate::api::auth::session; -use crate::api::fav::Fav; -use crate::api::ing::Ing; -use crate::api::news::News; -use crate::api::post::Post; -use crate::api::user::User; -use crate::args::cmd::post::{CreateCmd, UpdateCmd}; -use crate::args::parser::no_operation; -use crate::args::{parser, Args}; -use crate::infra::fp::currying::eq; -use crate::infra::infer::infer; -use crate::infra::iter::{ExactSizeIteratorExt, IntoIteratorExt}; -use crate::infra::option::OptionExt; -use crate::infra::result::WrapResult; -use anyhow::Result; -use clap::Parser; -use clap::{Command, CommandFactory}; -use colored::Colorize; -use std::env; - -pub mod api; -pub mod args; -pub mod display; -pub mod infra; - -fn show_non_printable_chars(text: String) -> String { - #[inline] - fn make_red(str: &str) -> String { - format!("{}", str.red()) - } - - text.replace(' ', &make_red("·")) - .replace('\0', &make_red("␀\0")) - .replace('\t', &make_red("␉\t")) - .replace('\n', &make_red("␊\n")) - .replace('\r', &make_red("␍\r")) - .replace("\r\n", &make_red("␍␊\r\n")) -} - -#[allow(clippy::missing_const_for_fn)] -fn panic_if_err(result: &Result) { - if let Err(e) = result { - panic!("{}", e) - } -} - -#[tokio::main(flavor = "multi_thread")] -async fn main() -> Result<()> { - let args_vec = env::args().collect::>(); - if args_vec.iter().any(eq(&"--debug".to_owned())) { - dbg!(args_vec); - } - - let args: Args = Args::parse(); - let global_opt = &args.global_opt; - if global_opt.debug { - dbg!(&args); - } - - let pat = global_opt.with_pat.clone().or_eval_result(session::get_pat); - let style = &global_opt.style; - let time_style = &global_opt.time_style; - let rev = args.rev; - let foe = global_opt.fail_on_error; - - let output = match args { - _ if let Some(pat) = parser::user::login(&args) => { - let cfg_path = session::login(pat); - foe.then(|| panic_if_err(&cfg_path)); - display::login(style, &cfg_path) - } - _ if parser::user::logout(&args) => { - let cfg_path = session::logout(); - foe.then(|| panic_if_err(&cfg_path)); - display::logout(style, &cfg_path) - } - _ if parser::user::user_info(&args) => { - let user_info = User::new(pat?).get_info().await; - foe.then(|| panic_if_err(&user_info)); - display::user_info(style, &user_info)? - } - _ if let Some((skip, take, r#type, align)) = parser::ing::list_ing(&args) => { - let ing_with_comment_iter = infer::>( - try { - let ing_api = Ing::new(pat?); - let ing_vec = ing_api.get_list(skip, take, &r#type).await?; - ing_vec - .into_iter() - .map(|ing| async { - let result = ing_api.get_comment_list(ing.id).await; - result.map(|comment_vec| (ing, comment_vec)) - }) - .join_all() - .await - .into_iter() - .collect::>>()? - }, - ) - .map(|vec| vec.into_iter().dyn_rev(rev)); - foe.then(|| panic_if_err(&ing_with_comment_iter)); - display::list_ing(style, time_style, ing_with_comment_iter, align)? - } - _ if let Some(content) = parser::ing::publish_ing(&args) => { - let content = try { - Ing::new(pat?).publish(content).await?; - content - }; - foe.then(|| panic_if_err(&content)); - display::publish_ing(style, &content) - } - _ if let Some((content, id)) = parser::ing::comment_ing(&args) => { - let content = try { - Ing::new(pat?) - .comment(id, content.clone(), None, None) - .await?; - content - }; - foe.then(|| panic_if_err(&content)); - display::comment_ing(style, &content) - } - _ if let Some(id) = parser::post::show_post(&args) => { - let entry = Post::new(pat?).get_one(id).await; - foe.then(|| panic_if_err(&entry)); - display::show_post(style, &entry)? - } - _ if let Some(id) = parser::post::show_post_meta(&args) => { - let entry = Post::new(pat?).get_one(id).await; - foe.then(|| panic_if_err(&entry)); - display::show_post_meta(style, time_style, &entry)? - } - _ if let Some(id) = parser::post::show_post_comment(&args) => { - let comment_iter = Post::new(pat?) - .get_comment_list(id) - .await - .map(|vec| vec.into_iter().dyn_rev(rev)); - foe.then(|| panic_if_err(&comment_iter)); - display::show_post_comment(style, time_style, comment_iter)? - } - _ if let Some((skip, take)) = parser::post::list_post(&args) => { - let meta_iter = Post::new(pat?) - .get_meta_list(skip, take) - .await - .map(|(vec, count)| (vec.into_iter().dyn_rev(rev), count)); - foe.then(|| panic_if_err(&meta_iter)); - display::list_post(style, meta_iter)? - } - _ if let Some(id) = parser::post::delete_post(&args) => { - let id = try { - Post::new(pat?).del_one(id).await?; - id - }; - foe.then(|| panic_if_err(&id)); - display::delete_post(style, &id) - } - _ if let Some((kw, skip, take)) = parser::post::search_self_post(&args) => { - let result = Post::new(pat?) - .search_self(skip, take, kw) - .await - .map(|(vec, count)| (vec.into_iter().dyn_rev(rev), count)); - foe.then(|| panic_if_err(&result)); - display::search_self_post(style, result)? - } - _ if let Some((kw, skip, take)) = parser::post::search_site_post(&args) => { - let result = Post::new(pat?) - .search_site(skip, take, kw) - .await - .map(|vec| vec.into_iter().dyn_rev(rev)); - foe.then(|| panic_if_err(&result)); - display::search_site_post(style, time_style, result)? - } - _ if let Some(create_cmd) = parser::post::create_post(&args) => { - let CreateCmd { - title, - body, - publish, - } = create_cmd; - let id = Post::new(pat?).create(title, body, *publish).await; - foe.then(|| panic_if_err(&id)); - display::create_post(style, &id) - } - _ if let Some((id, update_cmd)) = parser::post::update_post(&args) => { - let UpdateCmd { - title, - body, - publish, - } = update_cmd; - let id = Post::new(pat?).update(id, title, body, publish).await; - foe.then(|| panic_if_err(&id)); - display::update_post(style, &id) - } - _ if let Some((skip, take)) = parser::news::list_news(&args) => { - let news_iter = News::new(pat?) - .get_list(skip, take) - .await - .map(|vec| vec.into_iter().dyn_rev(rev)); - foe.then(|| panic_if_err(&news_iter)); - display::list_news(style, time_style, news_iter)? - } - _ if let Some((skip, take)) = parser::fav::list_fav(&args) => { - let fav_iter = Fav::new(pat?) - .get_list(skip, take) - .await - .map(|vec| vec.into_iter().dyn_rev(rev)); - foe.then(|| panic_if_err(&fav_iter)); - display::list_fav(style, time_style, fav_iter)? - } - - _ if no_operation(&args) => infer::(Args::command()).render_help().to_string(), - _ => "Invalid usage, follow '--help' for more information".to_owned(), - }; - - if global_opt.quiet { - return ().wrap_ok(); - } - - let output = { - let output = if output.ends_with("\n\n") { - output[..output.len() - 1].to_owned() - } else if output.ends_with('\n') { - output - } else { - format!("{}\n", output) - }; - if global_opt.debug { - show_non_printable_chars(output) - } else { - output - } - }; - - print!("{}", output); - - ().wrap_ok() -} From 558c9f7a16e6096ec7c704e3f9ca5c3d30210ec4 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Mon, 1 Jan 2024 23:56:32 +0800 Subject: [PATCH 03/10] Design the Cli API, move execute file to bin dir, change to lib --- README.zh-CN.md | 52 +++++++++ src/apis/mod.rs | 14 +++ src/apis/statuses/mod.rs | 13 +++ src/bin/cnb.rs | 241 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 12 ++ 5 files changed, 332 insertions(+) create mode 100644 README.zh-CN.md create mode 100644 src/apis/mod.rs create mode 100644 src/apis/statuses/mod.rs create mode 100644 src/bin/cnb.rs create mode 100644 src/lib.rs diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..197dea1 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,52 @@ +# Cnblogs 命令行工具 + +[![Build / Release](https://github.com/cnblogs/cli/actions/workflows/build-release.yml/badge.svg)](https://github.com/cnblogs/cli/actions/workflows/build-release.yml) +[![Build / Development](https://github.com/cnblogs/cli/actions/workflows/build-dev.yml/badge.svg)](https://github.com/cnblogs/cli/actions/workflows/build-dev.yml) + +从 CLI 访问 cnblogs。 + +## Cnbogs Cli 设计 + +从Cnblogs的[OpenAPI](https://api.cnblogs.com/help)来说,API主要有以下几类: + +1. Token: 认证 +2. Users: 仅提供当前登录用户信息 +3. Blogs: 博客的CURD及其评论的查看和增加, +4. Marks: 收藏的CURD +5. News: 新闻的查询,新闻评论的CURD +6. Statuses: 闪存CURD。 +7. Questions: 问题相关操作 +8. Edu: 班级相关 +9. Articles: 知识库的查找。 +10. Zzk: 找找看 + +### cli的使用 + +目前cli的使用如下: + +```shell +# Check your post list +cnb post --list +# Check your post +cnb --id 114514 post --show +# Create and publish post +cnb post create --title 'Hello' --body 'world!' --publish +# Change your post body +cnb --id 114514 post update --body 'niconiconiconi' + +# Show ing list +cnb ing list +# Publish ing +cnb ing --publish 'Hello world!' +# Comment to ing +cnb --id 114514 ing --comment 'Awesome!' + +# Check your user infomation +cnb user --info +``` + +大体上使用如上的设计,支持子命令,相关操作的设计按照RESTFUL的思路设计实现,博客的相关操作设计如下: + +```shell +cnb posts [comment] [list,create,query,delete,update] --[id/file/quertset] --[pagesize,pagecount] +``` diff --git a/src/apis/mod.rs b/src/apis/mod.rs new file mode 100644 index 0000000..b2fa28a --- /dev/null +++ b/src/apis/mod.rs @@ -0,0 +1,14 @@ +//! cnblogs 闪存接口模块 +//! +//! 封装[cnblogs Api](https://api.cnblogs.com/Help#0aee001a01835c83a3277a500ffc9040)至以下模块中: +//! +//! - statuses: 闪存相关api。 +//! - blogs: 博客相关 +//! - news: 新闻相关 +//! - questions: 问题相关 +//! - edu: edu 相关 +//! - user: 用户相关 +//! - token: 认证相关 +//! - marks: 收藏相关 + +pub mod statuses; diff --git a/src/apis/statuses/mod.rs b/src/apis/statuses/mod.rs new file mode 100644 index 0000000..2347f22 --- /dev/null +++ b/src/apis/statuses/mod.rs @@ -0,0 +1,13 @@ +//! cnblogs 闪存接口模块 +//! +//! 实现封装[cnblogs Api](https://api.cnblogs.com/Help#0aee001a01835c83a3277a500ffc9040)中的`Statuses`。 +//! +//! - 获取最新一条闪存内容 https://api.cnblogs.com/api/statuses/recent +//! - 发布闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments +//! - 获取闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments +//! - 删除闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments/{id} +//! - 发布闪存 https://api.cnblogs.com/api/statuses +//! - 删除闪存 https://api.cnblogs.com/api/statuses/{id} +//! - 根据类型获取闪存列表 https://api.cnblogs.com/api/statuses/@{type}?pageIndex={pageIndex}&pageSize={pageSize}&tag={tag} +//! - 根据Id获取闪存 https://api.cnblogs.com/api/statuses/{id} +//! diff --git a/src/bin/cnb.rs b/src/bin/cnb.rs new file mode 100644 index 0000000..64fe301 --- /dev/null +++ b/src/bin/cnb.rs @@ -0,0 +1,241 @@ +#![feature(try_blocks)] +#![feature(if_let_guard)] +#![feature(let_chains)] +#![feature(iterator_try_collect)] +#![feature(iterator_try_reduce)] +#![warn(clippy::all, clippy::nursery, clippy::cargo_common_metadata)] + +extern crate cnblogs_lib; + +use anyhow::Result; +use clap::Parser; +use clap::{Command, CommandFactory}; +use cnblogs_lib::api::auth::session; +use cnblogs_lib::api::fav::Fav; +use cnblogs_lib::api::ing::Ing; +use cnblogs_lib::api::news::News; +use cnblogs_lib::api::post::Post; +use cnblogs_lib::api::user::User; +use cnblogs_lib::args::cmd::post::{CreateCmd, UpdateCmd}; +use cnblogs_lib::args::parser::no_operation; +use cnblogs_lib::args::{parser, Args}; +use cnblogs_lib::display; +use cnblogs_lib::infra::fp::currying::eq; +use cnblogs_lib::infra::infer::infer; +use cnblogs_lib::infra::iter::{ExactSizeIteratorExt, IntoIteratorExt}; +use cnblogs_lib::infra::option::OptionExt; +use cnblogs_lib::infra::result::WrapResult; +use colored::Colorize; +use std::env; + +fn show_non_printable_chars(text: String) -> String { + #[inline] + fn make_red(str: &str) -> String { + format!("{}", str.red()) + } + + text.replace(' ', &make_red("·")) + .replace('\0', &make_red("␀\0")) + .replace('\t', &make_red("␉\t")) + .replace('\n', &make_red("␊\n")) + .replace('\r', &make_red("␍\r")) + .replace("\r\n", &make_red("␍␊\r\n")) +} + +#[allow(clippy::missing_const_for_fn)] +fn panic_if_err(result: &Result) { + if let Err(e) = result { + panic!("{}", e) + } +} + +#[tokio::main(flavor = "multi_thread")] +async fn main() -> Result<()> { + let args_vec = env::args().collect::>(); + if args_vec.iter().any(eq(&"--debug".to_owned())) { + dbg!(args_vec); + } + + let args: Args = Args::parse(); + let global_opt = &args.global_opt; + if global_opt.debug { + dbg!(&args); + } + + let pat = global_opt.with_pat.clone().or_eval_result(session::get_pat); + let style = &global_opt.style; + let time_style = &global_opt.time_style; + let rev = args.rev; + let foe = global_opt.fail_on_error; + + let output = match args { + _ if let Some(pat) = parser::user::login(&args) => { + let cfg_path = session::login(pat); + foe.then(|| panic_if_err(&cfg_path)); + display::login(style, &cfg_path) + } + _ if parser::user::logout(&args) => { + let cfg_path = session::logout(); + foe.then(|| panic_if_err(&cfg_path)); + display::logout(style, &cfg_path) + } + _ if parser::user::user_info(&args) => { + let user_info = User::new(pat?).get_info().await; + foe.then(|| panic_if_err(&user_info)); + display::user_info(style, &user_info)? + } + _ if let Some((skip, take, r#type, align)) = parser::ing::list_ing(&args) => { + let ing_with_comment_iter = infer::>( + try { + let ing_api = Ing::new(pat?); + let ing_vec = ing_api.get_list(skip, take, &r#type).await?; + ing_vec + .into_iter() + .map(|ing| async { + let result = ing_api.get_comment_list(ing.id).await; + result.map(|comment_vec| (ing, comment_vec)) + }) + .join_all() + .await + .into_iter() + .collect::>>()? + }, + ) + .map(|vec| vec.into_iter().dyn_rev(rev)); + foe.then(|| panic_if_err(&ing_with_comment_iter)); + display::list_ing(style, time_style, ing_with_comment_iter, align)? + } + _ if let Some(content) = parser::ing::publish_ing(&args) => { + let content = try { + Ing::new(pat?).publish(content).await?; + content + }; + foe.then(|| panic_if_err(&content)); + display::publish_ing(style, &content) + } + _ if let Some((content, id)) = parser::ing::comment_ing(&args) => { + let content = try { + Ing::new(pat?) + .comment(id, content.clone(), None, None) + .await?; + content + }; + foe.then(|| panic_if_err(&content)); + display::comment_ing(style, &content) + } + _ if let Some(id) = parser::post::show_post(&args) => { + let entry = Post::new(pat?).get_one(id).await; + foe.then(|| panic_if_err(&entry)); + display::show_post(style, &entry)? + } + _ if let Some(id) = parser::post::show_post_meta(&args) => { + let entry = Post::new(pat?).get_one(id).await; + foe.then(|| panic_if_err(&entry)); + display::show_post_meta(style, time_style, &entry)? + } + _ if let Some(id) = parser::post::show_post_comment(&args) => { + let comment_iter = Post::new(pat?) + .get_comment_list(id) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); + foe.then(|| panic_if_err(&comment_iter)); + display::show_post_comment(style, time_style, comment_iter)? + } + _ if let Some((skip, take)) = parser::post::list_post(&args) => { + let meta_iter = Post::new(pat?) + .get_meta_list(skip, take) + .await + .map(|(vec, count)| (vec.into_iter().dyn_rev(rev), count)); + foe.then(|| panic_if_err(&meta_iter)); + display::list_post(style, meta_iter)? + } + _ if let Some(id) = parser::post::delete_post(&args) => { + let id = try { + Post::new(pat?).del_one(id).await?; + id + }; + foe.then(|| panic_if_err(&id)); + display::delete_post(style, &id) + } + _ if let Some((kw, skip, take)) = parser::post::search_self_post(&args) => { + let result = Post::new(pat?) + .search_self(skip, take, kw) + .await + .map(|(vec, count)| (vec.into_iter().dyn_rev(rev), count)); + foe.then(|| panic_if_err(&result)); + display::search_self_post(style, result)? + } + _ if let Some((kw, skip, take)) = parser::post::search_site_post(&args) => { + let result = Post::new(pat?) + .search_site(skip, take, kw) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); + foe.then(|| panic_if_err(&result)); + display::search_site_post(style, time_style, result)? + } + _ if let Some(create_cmd) = parser::post::create_post(&args) => { + let CreateCmd { + title, + body, + publish, + .. + } = create_cmd; + let id = Post::new(pat?).create(title, body, *publish).await; + foe.then(|| panic_if_err(&id)); + display::create_post(style, &id) + } + _ if let Some((id, update_cmd)) = parser::post::update_post(&args) => { + let UpdateCmd { + title, + body, + publish, + .. + } = update_cmd; + let id = Post::new(pat?).update(id, title, body, publish).await; + foe.then(|| panic_if_err(&id)); + display::update_post(style, &id) + } + _ if let Some((skip, take)) = parser::news::list_news(&args) => { + let news_iter = News::new(pat?) + .get_list(skip, take) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); + foe.then(|| panic_if_err(&news_iter)); + display::list_news(style, time_style, news_iter)? + } + _ if let Some((skip, take)) = parser::fav::list_fav(&args) => { + let fav_iter = Fav::new(pat?) + .get_list(skip, take) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); + foe.then(|| panic_if_err(&fav_iter)); + display::list_fav(style, time_style, fav_iter)? + } + + _ if no_operation(&args) => infer::(Args::command()).render_help().to_string(), + _ => "Invalid usage, follow '--help' for more information".to_owned(), + }; + + if global_opt.quiet { + return ().wrap_ok(); + } + + let output = { + let output = if output.ends_with("\n\n") { + output[..output.len() - 1].to_owned() + } else if output.ends_with('\n') { + output + } else { + format!("{}\n", output) + }; + if global_opt.debug { + show_non_printable_chars(output) + } else { + output + } + }; + + print!("{}", output); + + ().wrap_ok() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..984f7bc --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,12 @@ +#![feature(try_blocks)] +#![feature(if_let_guard)] +#![feature(let_chains)] +#![feature(iterator_try_collect)] +#![feature(iterator_try_reduce)] +#![warn(clippy::all, clippy::nursery, clippy::cargo_common_metadata)] + +pub mod api; +pub mod apis; +pub mod args; +pub mod display; +pub mod infra; From 0a1e8b579fd9994af83a32277bca5153c069e0d8 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Fri, 12 Jan 2024 11:34:42 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E5=B0=81=E8=A3=85=E9=83=A8=E5=88=86openA?= =?UTF-8?q?pi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/ing/comment.rs | 77 +++++++++++++++ src/apis/ing/mod.rs | 197 +++++++++++++++++++++++++++++++++++++++ src/apis/mod.rs | 7 +- src/apis/statuses/mod.rs | 13 --- src/apis/token/mod.rs | 134 ++++++++++++++++++++++++++ 5 files changed, 414 insertions(+), 14 deletions(-) create mode 100644 src/apis/ing/comment.rs create mode 100644 src/apis/ing/mod.rs delete mode 100644 src/apis/statuses/mod.rs create mode 100644 src/apis/token/mod.rs diff --git a/src/apis/ing/comment.rs b/src/apis/ing/comment.rs new file mode 100644 index 0000000..163debc --- /dev/null +++ b/src/apis/ing/comment.rs @@ -0,0 +1,77 @@ +//! 闪存评论相关 +//! + +use anyhow::{Ok, Result}; +use reqwest::{Client, Response}; +use serde::{Deserialize, Serialize}; + +use crate::{infra::http::RequestBuilderExt, openapi}; + +/// 闪存评论及评论回复 +/// +/// replay_to: 在web端有一个ReplyToUserId,这里盲猜是这个 +/// parent_comment_id: 0 是对某条闪存评论,如果对闪存评论要回应,这里则是闪存评论的id +/// content: 评论内容。 如果是对闪存评论回应,则应加上`@用户名称` +/// +#[derive(Debug, Default, Deserialize, Serialize)] +#[serde(rename_all = "PascalCase")] +#[serde(default)] +pub struct StatusComment { + #[serde(skip)] + pub status_id: String, + pub replay_to: u64, + pub parent_comment_id: u64, + pub content: String, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct IngCommentEntry { + pub id: usize, + pub content: String, + #[serde(rename = "DateAdded")] + pub create_time: String, + pub status_id: usize, + pub user_alias: String, + #[serde(rename = "UserDisplayName")] + pub user_name: String, + pub user_icon_url: String, + pub user_id: usize, + pub user_guid: String, +} + +/// 根据闪存ID发表一个评论 +pub async fn post(token: String, sc: StatusComment) -> Result { + let r = Client::new() + .post(openapi!("/statuses/{}/comments", sc.parent_comment_id)) + .pat_auth(token.as_str()) + .form(&sc) + .send() + .await? + .error_for_status()?; + Ok(r) +} + +/// 根据闪存ID获取评论 +pub async fn get(token: &str, status_id: &str) -> Result> { + let r = Client::new() + .get(openapi!("/statuses/{}/comments", status_id)) + .pat_auth(token) + .send() + .await? + .error_for_status()? + .json() + .await?; + Ok(r) +} + +/// 根据闪存ID和commentid删除评论 +pub async fn delete(token: &str, status_id: &str, comment_id: &str) -> Result<()> { + Client::new() + .delete(openapi!("/statuses/{}/comments/{}", status_id, comment_id)) + .pat_auth(token) + .send() + .await? + .error_for_status()?; + Ok(()) +} diff --git a/src/apis/ing/mod.rs b/src/apis/ing/mod.rs new file mode 100644 index 0000000..7f76ffe --- /dev/null +++ b/src/apis/ing/mod.rs @@ -0,0 +1,197 @@ +//! cnblogs 闪存接口模块 +//! +//! 实现封装[cnblogs Api](https://api.cnblogs.com/Help#0aee001a01835c83a3277a500ffc9040)中的`Statuses`。 +//! +//! - 获取自己最新一条闪存内容 https://api.cnblogs.com/api/statuses/recent +//! - 发布闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments +//! - 获取闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments +//! - 删除闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments/{id} +//! - 发布闪存 https://api.cnblogs.com/api/statuses +//! - 删除闪存 https://api.cnblogs.com/api/statuses/{id} +//! - 根据类型获取闪存列表 https://api.cnblogs.com/api/statuses/@{type}?pageIndex={pageIndex}&pageSize={pageSize}&tag={tag} +//! - 根据Id获取闪存 https://api.cnblogs.com/api/statuses/{id} +//! + +pub mod comment; + +use anyhow::{Ok, Result}; +use reqwest::{Client, Response}; +use serde::{Deserialize, Serialize}; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +use crate::{infra::http::RequestBuilderExt, openapi}; + +#[derive(Debug, Default, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +#[serde(default)] +pub struct IngContent { + pub content: String, + pub is_private: bool, + pub client_type: IngSendFrom, +} + +#[derive(Clone, Debug, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum IngSendFrom { + None = 0, + Ms = 1, + GTalk = 2, + Qq = 3, + Sms = 5, + CellPhone = 6, + Web = 8, + VsCode = 9, + Cli = 13, +} + +impl Default for IngSendFrom { + fn default() -> Self { + return IngSendFrom::Cli; + } +} + +/// 查询条件,用于根据类别查询 +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(default)] +pub struct QeurySet { + #[serde(skip)] + pub types: QueryIngType, + pub page_index: u64, + pub page_size: u64, + #[serde(skip_serializing_if = "String::is_empty")] + pub tag: String, +} + +impl Default for QeurySet { + fn default() -> Self { + return Self { + types: QueryIngType::default(), + page_index: 1, + page_size: 30, + tag: "".to_string(), + }; + } +} + +/// +/// Follow = 1, 关注 +/// Myself = 4, 我的 +/// Public = 5, +/// RecentComment = 6, //新回应 +/// MyComment = 7, 我回应 +/// Tag = 10, tag 必填 +/// Comment = 13 回复我 +/// Mention = 14, +#[derive(Debug)] +pub enum QueryIngType { + Following, + My, + MyComment, + RecentComment, + Mention, + Comment, + All, +} + +impl Default for QueryIngType { + fn default() -> Self { + return Self::All; + } +} + +impl QueryIngType { + fn as_u8(&self) -> u8 { + match self { + QueryIngType::Following => 1, + QueryIngType::My => 4, + QueryIngType::All => 5, + QueryIngType::RecentComment => 6, + QueryIngType::MyComment => 7, + QueryIngType::Mention => 14, + QueryIngType::Comment => 13, + } + } +} + +/// 闪存详细内容。 +/// +/// 用于根据ID查询闪存的结果解析。 +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "PascalCase")] +pub struct IngEntry { + pub id: u64, + pub content: String, + pub is_private: bool, + pub is_lucky: bool, + pub comment_count: u64, + pub date_added: String, + pub user_alias: String, + pub user_display_name: String, + pub user_icon_url: String, + pub user_id: u64, + pub user_guid: String, + pub send_from: u8, + pub icons: String, +} + +pub async fn lastest(token: &str) -> Result { + let c = Client::new() + .get(openapi!("/statuses/recent")) + .pat_auth(token) + .send() + .await? + .error_for_status()?; + Ok(c) +} + +/// 根据条件查询 +/// +/// 如果是tag是,一定要传入Tag,tag是自己想查询的比如Linux,Debian,Python等等。 +/// 页数是从1开始的 +pub async fn query(token: &str, q: &QeurySet) -> Result> { + let r = Client::new() + .get(openapi!("/statuses/@{}", q.types.as_u8())) + .pat_auth(token) + .query(&q) + .send() + .await? + .error_for_status()? + .json::>() + .await?; + Ok(r) +} + +/// 根据ID查询 +pub async fn query_by_id(token: &str, id: &str) -> Result { + let r = Client::new() + .get(openapi!("/statuses/{}", id)) + .pat_auth(token) + .send() + .await? + .error_for_status()? + .json::() + .await?; + Ok(r) +} + +/// 发布一条闪存 +pub async fn post(token: &str, c: &IngContent) -> Result { + let r = Client::new() + .post(openapi!("/statuses")) + .pat_auth(token) + .json(c) + .send() + .await?; + Ok(r) +} + +/// 删除一条闪存 +pub async fn delete(token: &str, id: String) -> Result { + let r = Client::new() + .post(openapi!("/statuses/{}", id)) + .pat_auth(token) + .send() + .await?; + Ok(r) +} diff --git a/src/apis/mod.rs b/src/apis/mod.rs index b2fa28a..67572a9 100644 --- a/src/apis/mod.rs +++ b/src/apis/mod.rs @@ -11,4 +11,9 @@ //! - token: 认证相关 //! - marks: 收藏相关 -pub mod statuses; +pub mod ing; +pub mod token; + +pub const OAUTH_CLIENT: &str = "https://api.cnblogs.com/token"; +pub const OAUTH_TOKEN: &str = "https://oauth.cnblogs.com/connect/token"; +pub const OAUTHORIZE: &str = "https://oauth.cnblogs.com/connect/authorize"; diff --git a/src/apis/statuses/mod.rs b/src/apis/statuses/mod.rs deleted file mode 100644 index 2347f22..0000000 --- a/src/apis/statuses/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! cnblogs 闪存接口模块 -//! -//! 实现封装[cnblogs Api](https://api.cnblogs.com/Help#0aee001a01835c83a3277a500ffc9040)中的`Statuses`。 -//! -//! - 获取最新一条闪存内容 https://api.cnblogs.com/api/statuses/recent -//! - 发布闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments -//! - 获取闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments -//! - 删除闪存评论 https://api.cnblogs.com/api/statuses/{statusId}/comments/{id} -//! - 发布闪存 https://api.cnblogs.com/api/statuses -//! - 删除闪存 https://api.cnblogs.com/api/statuses/{id} -//! - 根据类型获取闪存列表 https://api.cnblogs.com/api/statuses/@{type}?pageIndex={pageIndex}&pageSize={pageSize}&tag={tag} -//! - 根据Id获取闪存 https://api.cnblogs.com/api/statuses/{id} -//! diff --git a/src/apis/token/mod.rs b/src/apis/token/mod.rs new file mode 100644 index 0000000..d41ff78 --- /dev/null +++ b/src/apis/token/mod.rs @@ -0,0 +1,134 @@ +//! Token +//! +//! TokenApi的封装 +//! +//! OAuth认证,提供两种方式接口。 +//! +//! 1. Client_Credentials +//! 2. Authorization_Code +//! + +use super::{OAUTH_CLIENT, OAUTH_TOKEN}; +use anyhow::Result; +use reqwest::Client; +use serde::{Deserialize, Serialize}; + +/// 认证授权后的授权 +/// +/// # Filed +/// +/// - access_token: Token String +/// - expires_in: 过期时间 +/// - token_type: Token认证方式 +/// - refresh_token: 过期后刷新Token,如果是ClientCredentials,此字段无用。 +/// - id_token: id,如果是ClientCredentials,此字段无用 +/// - scope: 客户端权限 +/// +#[derive(Debug, Serialize, Deserialize, Default)] +#[serde(default)] +pub struct OAuthToken { + pub id_token: String, + pub access_token: String, + pub expires_in: u64, + pub token_type: String, + pub refresh_token: String, + pub scope: String, +} + +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(default)] +pub struct ClientCredentialsReq { + pub client_id: String, + pub client_secret: String, + pub grant_type: String, +} + +pub async fn client_credentials(req: ClientCredentialsReq) -> Result { + let c = Client::new().post(OAUTH_CLIENT); + let r = c + .form(&req) + .send() + .await? + .error_for_status()? + .json::() + .await?; + Ok(r) +} + +/// OAuth 获取Token结构体 +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct OauthTokenReq { + // pub client_id: String, // string 是 授权ID client_id + // pub client_secret: String, // string 是 密钥 client_secret + // pub grant_type: String, // string 是 授权模式 authorization_code + #[serde(flatten)] + pub cc: ClientCredentialsReq, + pub code: String, // string 是 授权码 code + pub redirect_uri: String, // string 是 回调地址(默认) https://oauth.cnblogs.com/auth/callback +} + +impl OauthTokenReq { + pub fn new(client_id: String, client_secret: String, code: String) -> Self { + OauthTokenReq { + cc: ClientCredentialsReq { + client_id, + client_secret, + grant_type: "authorization_code".to_string(), + }, + code, + redirect_uri: "https://oauth.cnblogs.com/auth/callback".to_string(), + } + } +} + +/// 获取令牌 +pub async fn authorization_code(req: OauthTokenReq) -> Result { + let c = Client::new().post(OAUTH_TOKEN); + let r = c + .form(&req) + .send() + .await? + .error_for_status()? + .json::() + .await?; + Ok(r) +} + +/// OAuth 获取Token结构体 +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct RefreshTokenReq { + // pub client_id: String, + // pub client_secret: String, + // pub grant_type: String, + #[serde(flatten)] + pub cc: ClientCredentialsReq, + pub refresh_token: String, +} + +impl RefreshTokenReq { + pub fn new(client_id: String, client_secret: String, refresh_token: String) -> Self { + return RefreshTokenReq { + cc: ClientCredentialsReq { + client_id, + client_secret, + grant_type: "refresh_token".to_string(), + }, + refresh_token, + }; + } +} + +/// 刷新令牌 +/// +/// 令牌过期后重新获取。 +pub async fn refresh_token(req: RefreshTokenReq) -> Result { + let c = Client::new().post(OAUTH_TOKEN); + let r = c + .form(&req) + .send() + .await? + .error_for_status()? + .json::() + .await?; + Ok(r) +} From 04ca15e97e9bb64a31f39edf3d00b6f5d1267efd Mon Sep 17 00:00:00 2001 From: Roc Sun <710989028@qq.com> Date: Thu, 18 Jan 2024 18:15:37 +0800 Subject: [PATCH 05/10] refact:ing add query operate --- Cargo.toml | 1 + README.zh-CN.md | 13 +++++ src/apis/ing/mod.rs | 52 ++++++++++++----- src/args/cmd/ing.rs | 127 ++++++++++++++++++++++++++++++++++++++++- src/args/parser/ing.rs | 35 ++++++++++++ src/bin/cnb.rs | 8 +++ src/lib.rs | 1 + src/logic/ing.rs | 43 ++++++++++++++ src/logic/mod.rs | 6 ++ 9 files changed, 270 insertions(+), 16 deletions(-) create mode 100644 src/logic/ing.rs create mode 100644 src/logic/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 481b8a3..02684e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" repository = "https://github.com/cnblogs/cli" keywords = ["cli", "cnblogs", "blog"] categories = ["command-line-utilities"] +default-run = "cnb" [profile.dev] lto = true diff --git a/README.zh-CN.md b/README.zh-CN.md index 197dea1..89a95e9 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -50,3 +50,16 @@ cnb user --info ```shell cnb posts [comment] [list,create,query,delete,update] --[id/file/quertset] --[pagesize,pagecount] ``` + +## 闪存cli + +闪存cli设计如下: + +```sh +cnb ing query # 默认10条 +cnb ing query --id 123456 +cnb ing query --page 1 --count 10 +cnb ing query --type All --page 1 --count 10 --tag Linux +cnb ing create --conent hello --private false --lucky false +cnb ing delete --id 123456 +``` diff --git a/src/apis/ing/mod.rs b/src/apis/ing/mod.rs index 7f76ffe..ad17840 100644 --- a/src/apis/ing/mod.rs +++ b/src/apis/ing/mod.rs @@ -15,21 +15,34 @@ pub mod comment; use anyhow::{Ok, Result}; +use clap::{ValueEnum, Parser}; use reqwest::{Client, Response}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::{infra::http::RequestBuilderExt, openapi}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] #[serde(default)] pub struct IngContent { pub content: String, pub is_private: bool, + pub lucky: bool, pub client_type: IngSendFrom, } +impl Default for IngContent { + fn default() -> Self { + IngContent { + content: "".to_string(), + is_private: true, + lucky: false, + client_type: IngSendFrom::default(), + } + } +} + #[derive(Clone, Debug, Serialize_repr, Deserialize_repr)] #[repr(u8)] pub enum IngSendFrom { @@ -56,7 +69,7 @@ impl Default for IngSendFrom { #[serde(default)] pub struct QeurySet { #[serde(skip)] - pub types: QueryIngType, + pub r#type: QueryIngType, pub page_index: u64, pub page_size: u64, #[serde(skip_serializing_if = "String::is_empty")] @@ -66,9 +79,9 @@ pub struct QeurySet { impl Default for QeurySet { fn default() -> Self { return Self { - types: QueryIngType::default(), + r#type: QueryIngType::default(), page_index: 1, - page_size: 30, + page_size: 10, tag: "".to_string(), }; } @@ -83,15 +96,16 @@ impl Default for QeurySet { /// Tag = 10, tag 必填 /// Comment = 13 回复我 /// Mention = 14, -#[derive(Debug)] +#[derive(Debug, Clone, ValueEnum, Parser)] pub enum QueryIngType { - Following, - My, - MyComment, - RecentComment, - Mention, - Comment, - All, + Following = 1, + My = 4, + All = 5, + RecentComment = 6, + MyComment = 7, + Tag = 10, + Comment = 13, + Mention = 14, } impl Default for QueryIngType { @@ -100,6 +114,15 @@ impl Default for QueryIngType { } } +impl From for QueryIngType { + fn from(value: u8) -> Self { + match value { + 1 => Self::Following, + _ => Self::All, + } + } +} + impl QueryIngType { fn as_u8(&self) -> u8 { match self { @@ -108,6 +131,7 @@ impl QueryIngType { QueryIngType::All => 5, QueryIngType::RecentComment => 6, QueryIngType::MyComment => 7, + QueryIngType::Tag => 10, QueryIngType::Mention => 14, QueryIngType::Comment => 13, } @@ -151,7 +175,7 @@ pub async fn lastest(token: &str) -> Result { /// 页数是从1开始的 pub async fn query(token: &str, q: &QeurySet) -> Result> { let r = Client::new() - .get(openapi!("/statuses/@{}", q.types.as_u8())) + .get(openapi!("/statuses/@{}", q.r#type.as_u8())) .pat_auth(token) .query(&q) .send() @@ -163,7 +187,7 @@ pub async fn query(token: &str, q: &QeurySet) -> Result> { } /// 根据ID查询 -pub async fn query_by_id(token: &str, id: &str) -> Result { +pub async fn query_by_id(token: &str, id: &u64) -> Result { let r = Client::new() .get(openapi!("/statuses/{}", id)) .pat_auth(token) diff --git a/src/args/cmd/ing.rs b/src/args/cmd/ing.rs index 974c6bc..fe96460 100644 --- a/src/args/cmd/ing.rs +++ b/src/args/cmd/ing.rs @@ -1,5 +1,8 @@ -use crate::api::ing::IngType; -use clap::{Parser, Subcommand}; +use crate::{ + api::ing::IngType, + apis::{self, ing::QeurySet}, +}; +use clap::{Args, Parser, Subcommand, ValueEnum}; #[derive(Parser, Debug)] #[non_exhaustive] @@ -54,4 +57,124 @@ pub enum Cmd { #[arg(default_value_t = true)] align: bool, }, + + /// 根据条件查询闪存。 + Query(QueryIng), + + /// 创建闪存 + Create(CreateIng), + + /// 根据ID删除闪存 + Delete { + #[arg(long)] + id: Vec, + }, +} + +#[derive(Debug, Args)] +pub struct CreateIng { + /// 闪存内容 + // #[arg(short, long)] + content: Option, + #[arg(short, long, default_value_t = true)] + private: bool, + + #[arg(short, long, default_value_t = false)] + lucky: bool, + + #[arg(short, long)] + tag: Option, +} + +#[derive(Args, Debug)] +struct Create { + /// 闪存内容 + content: String, + + /// 是否私有,默认是全站 + #[arg(short, long, default_value_t = true)] + private: bool, + + /// 是否发布为幸运 + #[arg(short, long, default_value_t = false)] + lucky: bool, + + /// 是否发布在某个标签下,默认不发布标签。 + #[arg(short, long, default_value = "")] + tag: String, +} + +/// 查询参数 +/// 当使用type为 +#[derive(Debug, Args, Clone)] +pub struct QueryIng { + /// 查询类型 + #[arg( + short, + long, + value_name = "TYPE", + default_value_t = QueryType::F, + default_missing_value = "f", + value_enum + )] + pub r#type: QueryType, + /// 分页查询,起始索引是1 + #[arg(short('n'), long, default_value_t = 1)] + pub page_index: u64, + /// 分页查询数量, 默认是10 + #[arg(short('s'), long, default_value_t = 10)] + pub page_size: u64, + /// 按照标签查询 + #[arg(short('g'), long)] + pub tag: Option, + /// 根据ID查询 + #[arg(short, long)] + pub id: Option>, +} + +impl From<&QueryIng> for QeurySet { + fn from(value: &QueryIng) -> Self { + Self { + r#type: value.r#type.clone().into(), + page_index: value.page_index, + page_size: value.page_size, + tag: value.tag.clone().unwrap_or_default(), + } + } +} + +/// 过滤的类型 +#[derive(Debug, Clone, ValueEnum, Parser)] +pub enum QueryType { + /// 关注 + F = 1, + /// 我的 + My = 4, + /// 全站 + P = 5, + /// 新回应 + Rc = 6, + /// 我回应 + Mc = 7, + /// 按照Tag过滤,使用T时,如果没有Query::tag或者站点不存在,则不会有结果。 + T = 10, + /// 回复我 + C = 13, + /// 提到我 + M = 14, +} + +impl From for apis::ing::QueryIngType { + fn from(value: QueryType) -> Self { + match value { + QueryType::F => Self::Following, + QueryType::My => Self::My, + QueryType::P => Self::All, + QueryType::Rc => Self::RecentComment, + QueryType::Mc => Self::MyComment, + QueryType::T => Self::Tag, + QueryType::C => Self::Comment, + QueryType::M => Self::Mention, + } + } } diff --git a/src/args/parser/ing.rs b/src/args/parser/ing.rs index 62ed32b..2c8e42c 100644 --- a/src/args/parser/ing.rs +++ b/src/args/parser/ing.rs @@ -1,4 +1,5 @@ use crate::api::ing::IngType; +use crate::args::cmd::ing::QueryIng; use crate::args::parser::{get_skip, get_take}; use crate::args::{cmd, Args, Cmd}; use crate::infra::option::WrapOption; @@ -67,3 +68,37 @@ pub fn comment_ing(args: &Args) -> Option<(&String, usize)> { } .wrap_some() } + +#[allow(unused)] +pub fn query(args: &Args) -> Option { + match args { + Args { + cmd: + Some(Cmd::Ing(cmd::ing::Opt { + cmd: + Some(cmd::ing::Cmd::Query(QueryIng { + r#type, + page_index, + page_size, + tag, + id, + })), + publish: None, + comment: None, + })), + id: None, + rev: _, + skip, + take, + global_opt: _, + } => QueryIng { + r#type: r#type.clone(), + page_index: page_index.clone(), + page_size: page_size.clone(), + tag: tag.clone(), + id: id.clone(), + }, + _ => return None, + } + .wrap_some() +} diff --git a/src/bin/cnb.rs b/src/bin/cnb.rs index 64fe301..0a5c1ae 100644 --- a/src/bin/cnb.rs +++ b/src/bin/cnb.rs @@ -25,6 +25,7 @@ use cnblogs_lib::infra::infer::infer; use cnblogs_lib::infra::iter::{ExactSizeIteratorExt, IntoIteratorExt}; use cnblogs_lib::infra::option::OptionExt; use cnblogs_lib::infra::result::WrapResult; +use cnblogs_lib::logic::ing::get_ings_and_comments; use colored::Colorize; use std::env; @@ -84,6 +85,13 @@ async fn main() -> Result<()> { foe.then(|| panic_if_err(&user_info)); display::user_info(style, &user_info)? } + + _ if let Some(q) = parser::ing::query(&args) => { + + get_ings_and_comments(pat.unwrap().as_str(), &q).await; + "".to_string() + } + _ if let Some((skip, take, r#type, align)) = parser::ing::list_ing(&args) => { let ing_with_comment_iter = infer::>( try { diff --git a/src/lib.rs b/src/lib.rs index 984f7bc..4c7b191 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,3 +10,4 @@ pub mod apis; pub mod args; pub mod display; pub mod infra; +pub mod logic; diff --git a/src/logic/ing.rs b/src/logic/ing.rs new file mode 100644 index 0000000..a79f2f7 --- /dev/null +++ b/src/logic/ing.rs @@ -0,0 +1,43 @@ +//! 闪存相关逻辑 +//! + +use crate::{ + apis::ing::{query_by_id, query as iq}, + args::cmd::ing::QueryIng, + infra::iter::IntoIteratorExt, +}; + +pub async fn get_ings_and_comments(t: &str, q: &QueryIng) { + println!("{:?}", q); + if let Some(ids) = &q.id { + let a = ids + .iter() + .map(|id| async move { query_by_id(t, id).await }) + .join_all() + .await + ; + + a.iter().for_each(|i| { + match i { + Ok(e) => { + println!("{:?}", e); + } + Err(e) => { + eprintln!("{:?}", e); + } + } + }) + + } + + let a: Result, anyhow::Error> = iq(t, &q.into()).await; + match a { + Ok(e) => { + println!("{:?}", e); + } + Err(e) => { + eprintln!("{:?}", e); + } + } + +} diff --git a/src/logic/mod.rs b/src/logic/mod.rs new file mode 100644 index 0000000..b9ab01d --- /dev/null +++ b/src/logic/mod.rs @@ -0,0 +1,6 @@ +//! cli操作逻辑 +//! +//! 此模块暂定封装操作逻辑,比如是闪存的curd,闪存评论的curd。 +//! + +pub mod ing; \ No newline at end of file From 338a3c7fa7a52e994c64c984db23a3df55bfdc30 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Tue, 23 Jan 2024 23:22:29 +0800 Subject: [PATCH 06/10] refactor-ing: refactor ing command, add query, create, delete subcommands --- README.zh-CN.md | 15 ++++-- src/apis/ing/comment.rs | 18 +------ src/apis/ing/mod.rs | 58 +++++++--------------- src/args/cmd/ing.rs | 52 ++++++++++---------- src/args/parser/ing.rs | 58 +++++++++++++++++++++- src/bin/cnb.rs | 20 ++++++-- src/logic/ing.rs | 103 ++++++++++++++++++++++++++++++---------- src/logic/mod.rs | 6 +-- 8 files changed, 208 insertions(+), 122 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index 89a95e9..a58b5d5 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -56,10 +56,15 @@ cnb posts [comment] [list,create,query,delete,update] --[id/file/quertset] --[pa 闪存cli设计如下: ```sh -cnb ing query # 默认10条 -cnb ing query --id 123456 -cnb ing query --page 1 --count 10 -cnb ing query --type All --page 1 --count 10 --tag Linux -cnb ing create --conent hello --private false --lucky false +cnb ing query # 默认10条s +cnb ing query --id 123456 --id 123 +cnb ing query -n 1 -s 10 +cnb ing query --type f -n 2 -s 10 +# 根据tag查找,-g为tag名称 -n 2 -s 10 分页 +cnb ing query -t t -g Linux +cnb ing create hello --private --lucky +cnb ing create hello --private --lucky --tag hello cnb ing delete --id 123456 ``` + +TODO: “提到我”存在解析问题。待完善。 diff --git a/src/apis/ing/comment.rs b/src/apis/ing/comment.rs index 163debc..c6ae97a 100644 --- a/src/apis/ing/comment.rs +++ b/src/apis/ing/comment.rs @@ -5,7 +5,7 @@ use anyhow::{Ok, Result}; use reqwest::{Client, Response}; use serde::{Deserialize, Serialize}; -use crate::{infra::http::RequestBuilderExt, openapi}; +use crate::{api::ing::get_comment_list::IngCommentEntry, infra::http::RequestBuilderExt, openapi}; /// 闪存评论及评论回复 /// @@ -24,22 +24,6 @@ pub struct StatusComment { pub content: String, } -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct IngCommentEntry { - pub id: usize, - pub content: String, - #[serde(rename = "DateAdded")] - pub create_time: String, - pub status_id: usize, - pub user_alias: String, - #[serde(rename = "UserDisplayName")] - pub user_name: String, - pub user_icon_url: String, - pub user_id: usize, - pub user_guid: String, -} - /// 根据闪存ID发表一个评论 pub async fn post(token: String, sc: StatusComment) -> Result { let r = Client::new() diff --git a/src/apis/ing/mod.rs b/src/apis/ing/mod.rs index ad17840..8364481 100644 --- a/src/apis/ing/mod.rs +++ b/src/apis/ing/mod.rs @@ -15,12 +15,15 @@ pub mod comment; use anyhow::{Ok, Result}; -use clap::{ValueEnum, Parser}; +use clap::{Parser, ValueEnum}; use reqwest::{Client, Response}; use serde::{Deserialize, Serialize}; -use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::{infra::http::RequestBuilderExt, openapi}; +use crate::{ + api::ing::{get_list::IngEntry, IngSendFrom}, + infra::http::RequestBuilderExt, + openapi, +}; #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] @@ -43,20 +46,6 @@ impl Default for IngContent { } } -#[derive(Clone, Debug, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum IngSendFrom { - None = 0, - Ms = 1, - GTalk = 2, - Qq = 3, - Sms = 5, - CellPhone = 6, - Web = 8, - VsCode = 9, - Cli = 13, -} - impl Default for IngSendFrom { fn default() -> Self { return IngSendFrom::Cli; @@ -90,12 +79,12 @@ impl Default for QeurySet { /// /// Follow = 1, 关注 /// Myself = 4, 我的 -/// Public = 5, -/// RecentComment = 6, //新回应 +/// Public = 5, 全站 +/// RecentComment = 6, 新回应 /// MyComment = 7, 我回应 /// Tag = 10, tag 必填 /// Comment = 13 回复我 -/// Mention = 14, +/// Mention = 14, @我 #[derive(Debug, Clone, ValueEnum, Parser)] pub enum QueryIngType { Following = 1, @@ -118,6 +107,12 @@ impl From for QueryIngType { fn from(value: u8) -> Self { match value { 1 => Self::Following, + 4 => Self::My, + 6 => Self::RecentComment, + 7 => Self::MyComment, + 10 => Self::Tag, + 13 => Self::Comment, + 14 => Self::Mention, _ => Self::All, } } @@ -138,27 +133,6 @@ impl QueryIngType { } } -/// 闪存详细内容。 -/// -/// 用于根据ID查询闪存的结果解析。 -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct IngEntry { - pub id: u64, - pub content: String, - pub is_private: bool, - pub is_lucky: bool, - pub comment_count: u64, - pub date_added: String, - pub user_alias: String, - pub user_display_name: String, - pub user_icon_url: String, - pub user_id: u64, - pub user_guid: String, - pub send_from: u8, - pub icons: String, -} - pub async fn lastest(token: &str) -> Result { let c = Client::new() .get(openapi!("/statuses/recent")) @@ -211,7 +185,7 @@ pub async fn post(token: &str, c: &IngContent) -> Result { } /// 删除一条闪存 -pub async fn delete(token: &str, id: String) -> Result { +pub async fn delete(token: &str, id: u64) -> Result { let r = Client::new() .post(openapi!("/statuses/{}", id)) .pat_auth(token) diff --git a/src/args/cmd/ing.rs b/src/args/cmd/ing.rs index fe96460..96b050e 100644 --- a/src/args/cmd/ing.rs +++ b/src/args/cmd/ing.rs @@ -1,6 +1,9 @@ use crate::{ - api::ing::IngType, - apis::{self, ing::QeurySet}, + api::ing::{IngType, IngSendFrom}, + apis::{ + self, + ing::{IngContent, QeurySet}, + }, }; use clap::{Args, Parser, Subcommand, ValueEnum}; @@ -59,49 +62,48 @@ pub enum Cmd { }, /// 根据条件查询闪存。 + /// Query(QueryIng), /// 创建闪存 Create(CreateIng), /// 根据ID删除闪存 - Delete { - #[arg(long)] - id: Vec, - }, + Delete { id: Vec }, } #[derive(Debug, Args)] pub struct CreateIng { /// 闪存内容 - // #[arg(short, long)] - content: Option, - #[arg(short, long, default_value_t = true)] - private: bool, - - #[arg(short, long, default_value_t = false)] - lucky: bool, - - #[arg(short, long)] - tag: Option, -} - -#[derive(Args, Debug)] -struct Create { - /// 闪存内容 - content: String, + pub content: String, /// 是否私有,默认是全站 #[arg(short, long, default_value_t = true)] - private: bool, + pub private: bool, /// 是否发布为幸运 #[arg(short, long, default_value_t = false)] - lucky: bool, + pub lucky: bool, /// 是否发布在某个标签下,默认不发布标签。 #[arg(short, long, default_value = "")] - tag: String, + pub tag: String, +} + +impl From for IngContent { + fn from(value: CreateIng) -> Self { + let mut cont = String::new(); + if !value.tag.is_empty() { + cont.push_str(format!("[{}]", value.tag).as_str()) + } + cont.push_str(value.content.as_str()); + Self { + content: cont, + is_private: value.private, + lucky: value.lucky, + client_type: IngSendFrom::Cli + } + } } /// 查询参数 diff --git a/src/args/parser/ing.rs b/src/args/parser/ing.rs index 2c8e42c..e458a47 100644 --- a/src/args/parser/ing.rs +++ b/src/args/parser/ing.rs @@ -1,5 +1,5 @@ use crate::api::ing::IngType; -use crate::args::cmd::ing::QueryIng; +use crate::args::cmd::ing::{QueryIng, CreateIng}; use crate::args::parser::{get_skip, get_take}; use crate::args::{cmd, Args, Cmd}; use crate::infra::option::WrapOption; @@ -102,3 +102,59 @@ pub fn query(args: &Args) -> Option { } .wrap_some() } + + +#[allow(unused)] +pub fn create_ing(args: &Args) -> Option { + match args { + Args { + cmd: + Some(Cmd::Ing(cmd::ing::Opt { + cmd: + Some(cmd::ing::Cmd::Create(CreateIng { + content, + private, + lucky, + tag, + })), + publish: None, + comment: None, + })), + id: None, + rev: _, + skip, + take, + global_opt: _, + } => CreateIng { + content: content.clone(), + private:private.clone(), + lucky: lucky.clone(), + tag: tag.clone(), + }, + _ => return None, + } + .wrap_some() +} + + +#[allow(unused)] +pub fn delete(args: &Args) -> Option> { + match args { + Args { + cmd: + Some(Cmd::Ing(cmd::ing::Opt { + cmd: + Some(cmd::ing::Cmd::Delete{id}), + publish: None, + comment: None, + })), + id: None, + rev: _, + skip, + take, + global_opt: _, + } => id.clone(), + _ => return None, + } + .wrap_some() +} diff --git a/src/bin/cnb.rs b/src/bin/cnb.rs index 0a5c1ae..4523e1d 100644 --- a/src/bin/cnb.rs +++ b/src/bin/cnb.rs @@ -19,13 +19,12 @@ use cnblogs_lib::api::user::User; use cnblogs_lib::args::cmd::post::{CreateCmd, UpdateCmd}; use cnblogs_lib::args::parser::no_operation; use cnblogs_lib::args::{parser, Args}; -use cnblogs_lib::display; +use cnblogs_lib::{display, logic}; use cnblogs_lib::infra::fp::currying::eq; use cnblogs_lib::infra::infer::infer; use cnblogs_lib::infra::iter::{ExactSizeIteratorExt, IntoIteratorExt}; use cnblogs_lib::infra::option::OptionExt; use cnblogs_lib::infra::result::WrapResult; -use cnblogs_lib::logic::ing::get_ings_and_comments; use colored::Colorize; use std::env; @@ -87,8 +86,23 @@ async fn main() -> Result<()> { } _ if let Some(q) = parser::ing::query(&args) => { + let ing_with_comment_iter = logic::ing::get_ings_and_comments(pat.unwrap().as_str(), &q) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); + + foe.then(|| panic_if_err(&ing_with_comment_iter)); + display::list_ing(style, time_style, ing_with_comment_iter, true)? + } + + _ if let Some(ids) = parser::ing::delete(&args) => { + let a = pat.as_ref().unwrap().as_str(); + logic::ing::delete_by_ing_id(a, ids).await; + "".to_string() + } - get_ings_and_comments(pat.unwrap().as_str(), &q).await; + _ if let Some(ci) = parser::ing::create_ing(&args) => { + let a = pat.as_ref().unwrap().as_str(); + logic::ing::create_ing_with_arg(a, ci).await; "".to_string() } diff --git a/src/logic/ing.rs b/src/logic/ing.rs index a79f2f7..c17f8b6 100644 --- a/src/logic/ing.rs +++ b/src/logic/ing.rs @@ -1,43 +1,94 @@ //! 闪存相关逻辑 //! +use anyhow::{Ok, Result}; + use crate::{ - apis::ing::{query_by_id, query as iq}, - args::cmd::ing::QueryIng, + api::{ + self, + ing::{get_comment_list::IngCommentEntry, get_list::IngEntry}, + }, + apis::ing::{comment, delete, query as iq, query_by_id, post}, + args::cmd::ing::{QueryIng, CreateIng}, infra::iter::IntoIteratorExt, }; -pub async fn get_ings_and_comments(t: &str, q: &QueryIng) { - println!("{:?}", q); +/// 根据queryset查询 +/// TODO: 提到我和我评论的解析存在问题。 +pub async fn get_ings_and_comments( + t: &str, + q: &QueryIng, +) -> Result)>> { if let Some(ids) = &q.id { let a = ids .iter() .map(|id| async move { query_by_id(t, id).await }) .join_all() .await - ; - - a.iter().for_each(|i| { - match i { - Ok(e) => { - println!("{:?}", e); + .into_iter() + .filter(|x| { + if x.is_err() { + eprintln!("{}", x.as_ref().err().unwrap()) } - Err(e) => { - eprintln!("{:?}", e); - } - } - }) - - } - - let a: Result, anyhow::Error> = iq(t, &q.into()).await; - match a { - Ok(e) => { - println!("{:?}", e); - } - Err(e) => { - eprintln!("{:?}", e); - } + x.is_ok() + }) + .map(|x| x.unwrap()) + .collect::>(); + + return get_ing_comments(t, a).await; + } else { + let a = iq(t, &q.into()) + .await? + .into_iter() + .map(|x| x.into()) + .collect::>(); + return get_ing_comments(t, a).await; } +} +// TODO: 分类细化 +/// 初步提取公共部分 +pub async fn get_ing_comments( + t: &str, + i: Vec, +) -> Result)>> { + let a = i + .into_iter() + .map(|ing| async { + let result = comment::get(t, ing.id.to_string().as_str()).await; + result.map(|comment_vec| (ing, comment_vec)) + }) + .join_all() + .await + .into_iter() + .collect::>>()?; + Ok(a) +} + +/// 通过ID删除 +pub async fn delete_by_ing_id(t: &str, ids: Vec) { + ids.into_iter() + .map(|id| async move { delete(t, id).await }) + .join_all() + .await + .iter() + .for_each(|x| { + if x.is_err() { + eprintln!("{:?}", x.as_ref().err().unwrap().to_string()) + } + }); +} + +/// 创建闪存 +pub async fn create_ing_with_arg(t:&str, c: CreateIng) { + let cc = c.into(); + let e = post(t, &cc) + .await + ; + + if e.is_err() { + eprintln!("{:?}", e.as_ref().err().unwrap().to_string()); + } else { + println!("🙈 ! {:?}", cc.content); + } } diff --git a/src/logic/mod.rs b/src/logic/mod.rs index b9ab01d..14d8057 100644 --- a/src/logic/mod.rs +++ b/src/logic/mod.rs @@ -1,6 +1,6 @@ //! cli操作逻辑 -//! +//! //! 此模块暂定封装操作逻辑,比如是闪存的curd,闪存评论的curd。 -//! +//! -pub mod ing; \ No newline at end of file +pub mod ing; From d5ebc0e970ff91dd3bb93d5f6960994eabf3ffac Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Wed, 24 Jan 2024 15:29:39 +0800 Subject: [PATCH 07/10] fix:RUSTSEC-2024-0003 --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd007c8..096293d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,9 +483,9 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "h2" -version = "0.3.20" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -493,7 +493,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.0.0", "slab", "tokio", "tokio-util", From f18a785d5b814e4c6672fe2c9f0cff81f44c2c43 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Wed, 24 Jan 2024 15:55:07 +0800 Subject: [PATCH 08/10] fmt code --- src/args/cmd/ing.rs | 6 +++--- src/args/parser/ing.rs | 9 +++------ src/bin/cnb.rs | 9 +++++---- src/logic/ing.rs | 10 ++++------ 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/args/cmd/ing.rs b/src/args/cmd/ing.rs index 96b050e..6459a70 100644 --- a/src/args/cmd/ing.rs +++ b/src/args/cmd/ing.rs @@ -1,5 +1,5 @@ use crate::{ - api::ing::{IngType, IngSendFrom}, + api::ing::{IngSendFrom, IngType}, apis::{ self, ing::{IngContent, QeurySet}, @@ -62,7 +62,7 @@ pub enum Cmd { }, /// 根据条件查询闪存。 - /// + /// Query(QueryIng), /// 创建闪存 @@ -101,7 +101,7 @@ impl From for IngContent { content: cont, is_private: value.private, lucky: value.lucky, - client_type: IngSendFrom::Cli + client_type: IngSendFrom::Cli, } } } diff --git a/src/args/parser/ing.rs b/src/args/parser/ing.rs index e458a47..874c869 100644 --- a/src/args/parser/ing.rs +++ b/src/args/parser/ing.rs @@ -1,5 +1,5 @@ use crate::api::ing::IngType; -use crate::args::cmd::ing::{QueryIng, CreateIng}; +use crate::args::cmd::ing::{CreateIng, QueryIng}; use crate::args::parser::{get_skip, get_take}; use crate::args::{cmd, Args, Cmd}; use crate::infra::option::WrapOption; @@ -103,7 +103,6 @@ pub fn query(args: &Args) -> Option { .wrap_some() } - #[allow(unused)] pub fn create_ing(args: &Args) -> Option { match args { @@ -127,7 +126,7 @@ pub fn create_ing(args: &Args) -> Option { global_opt: _, } => CreateIng { content: content.clone(), - private:private.clone(), + private: private.clone(), lucky: lucky.clone(), tag: tag.clone(), }, @@ -136,15 +135,13 @@ pub fn create_ing(args: &Args) -> Option { .wrap_some() } - #[allow(unused)] pub fn delete(args: &Args) -> Option> { match args { Args { cmd: Some(Cmd::Ing(cmd::ing::Opt { - cmd: - Some(cmd::ing::Cmd::Delete{id}), + cmd: Some(cmd::ing::Cmd::Delete { id }), publish: None, comment: None, })), diff --git a/src/bin/cnb.rs b/src/bin/cnb.rs index 4523e1d..298b60a 100644 --- a/src/bin/cnb.rs +++ b/src/bin/cnb.rs @@ -19,12 +19,12 @@ use cnblogs_lib::api::user::User; use cnblogs_lib::args::cmd::post::{CreateCmd, UpdateCmd}; use cnblogs_lib::args::parser::no_operation; use cnblogs_lib::args::{parser, Args}; -use cnblogs_lib::{display, logic}; use cnblogs_lib::infra::fp::currying::eq; use cnblogs_lib::infra::infer::infer; use cnblogs_lib::infra::iter::{ExactSizeIteratorExt, IntoIteratorExt}; use cnblogs_lib::infra::option::OptionExt; use cnblogs_lib::infra::result::WrapResult; +use cnblogs_lib::{display, logic}; use colored::Colorize; use std::env; @@ -86,9 +86,10 @@ async fn main() -> Result<()> { } _ if let Some(q) = parser::ing::query(&args) => { - let ing_with_comment_iter = logic::ing::get_ings_and_comments(pat.unwrap().as_str(), &q) - .await - .map(|vec| vec.into_iter().dyn_rev(rev)); + let ing_with_comment_iter = + logic::ing::get_ings_and_comments(pat.unwrap().as_str(), &q) + .await + .map(|vec| vec.into_iter().dyn_rev(rev)); foe.then(|| panic_if_err(&ing_with_comment_iter)); display::list_ing(style, time_style, ing_with_comment_iter, true)? diff --git a/src/logic/ing.rs b/src/logic/ing.rs index c17f8b6..76fd3f9 100644 --- a/src/logic/ing.rs +++ b/src/logic/ing.rs @@ -8,8 +8,8 @@ use crate::{ self, ing::{get_comment_list::IngCommentEntry, get_list::IngEntry}, }, - apis::ing::{comment, delete, query as iq, query_by_id, post}, - args::cmd::ing::{QueryIng, CreateIng}, + apis::ing::{comment, delete, post, query as iq, query_by_id}, + args::cmd::ing::{CreateIng, QueryIng}, infra::iter::IntoIteratorExt, }; @@ -80,11 +80,9 @@ pub async fn delete_by_ing_id(t: &str, ids: Vec) { } /// 创建闪存 -pub async fn create_ing_with_arg(t:&str, c: CreateIng) { +pub async fn create_ing_with_arg(t: &str, c: CreateIng) { let cc = c.into(); - let e = post(t, &cc) - .await - ; + let e = post(t, &cc).await; if e.is_err() { eprintln!("{:?}", e.as_ref().err().unwrap().to_string()); From 571bac6c7dd9a480938dcec60eb72ee8d2920275 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Wed, 24 Jan 2024 16:13:38 +0800 Subject: [PATCH 09/10] fmt code --- src/apis/ing/mod.rs | 28 ++++++++++++++-------------- src/apis/token/mod.rs | 6 +++--- src/args/parser/ing.rs | 8 ++++---- src/logic/ing.rs | 5 ++--- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/apis/ing/mod.rs b/src/apis/ing/mod.rs index 8364481..ee9243f 100644 --- a/src/apis/ing/mod.rs +++ b/src/apis/ing/mod.rs @@ -37,7 +37,7 @@ pub struct IngContent { impl Default for IngContent { fn default() -> Self { - IngContent { + Self { content: "".to_string(), is_private: true, lucky: false, @@ -48,7 +48,7 @@ impl Default for IngContent { impl Default for IngSendFrom { fn default() -> Self { - return IngSendFrom::Cli; + Self::Cli } } @@ -67,12 +67,12 @@ pub struct QeurySet { impl Default for QeurySet { fn default() -> Self { - return Self { + Self { r#type: QueryIngType::default(), page_index: 1, page_size: 10, tag: "".to_string(), - }; + } } } @@ -99,7 +99,7 @@ pub enum QueryIngType { impl Default for QueryIngType { fn default() -> Self { - return Self::All; + Self::All } } @@ -119,16 +119,16 @@ impl From for QueryIngType { } impl QueryIngType { - fn as_u8(&self) -> u8 { + const fn as_u8(&self) -> u8 { match self { - QueryIngType::Following => 1, - QueryIngType::My => 4, - QueryIngType::All => 5, - QueryIngType::RecentComment => 6, - QueryIngType::MyComment => 7, - QueryIngType::Tag => 10, - QueryIngType::Mention => 14, - QueryIngType::Comment => 13, + Self::Following => 1, + Self::My => 4, + Self::All => 5, + Self::RecentComment => 6, + Self::MyComment => 7, + Self::Tag => 10, + Self::Mention => 14, + Self::Comment => 13, } } } diff --git a/src/apis/token/mod.rs b/src/apis/token/mod.rs index d41ff78..be6b877 100644 --- a/src/apis/token/mod.rs +++ b/src/apis/token/mod.rs @@ -69,7 +69,7 @@ pub struct OauthTokenReq { impl OauthTokenReq { pub fn new(client_id: String, client_secret: String, code: String) -> Self { - OauthTokenReq { + Self { cc: ClientCredentialsReq { client_id, client_secret, @@ -107,14 +107,14 @@ pub struct RefreshTokenReq { impl RefreshTokenReq { pub fn new(client_id: String, client_secret: String, refresh_token: String) -> Self { - return RefreshTokenReq { + Self { cc: ClientCredentialsReq { client_id, client_secret, grant_type: "refresh_token".to_string(), }, refresh_token, - }; + } } } diff --git a/src/args/parser/ing.rs b/src/args/parser/ing.rs index 874c869..dc5991c 100644 --- a/src/args/parser/ing.rs +++ b/src/args/parser/ing.rs @@ -93,8 +93,8 @@ pub fn query(args: &Args) -> Option { global_opt: _, } => QueryIng { r#type: r#type.clone(), - page_index: page_index.clone(), - page_size: page_size.clone(), + page_index: *page_index, + page_size: *page_size, tag: tag.clone(), id: id.clone(), }, @@ -126,8 +126,8 @@ pub fn create_ing(args: &Args) -> Option { global_opt: _, } => CreateIng { content: content.clone(), - private: private.clone(), - lucky: lucky.clone(), + private: *private, + lucky: *lucky, tag: tag.clone(), }, _ => return None, diff --git a/src/logic/ing.rs b/src/logic/ing.rs index 76fd3f9..53862ed 100644 --- a/src/logic/ing.rs +++ b/src/logic/ing.rs @@ -35,14 +35,13 @@ pub async fn get_ings_and_comments( .map(|x| x.unwrap()) .collect::>(); - return get_ing_comments(t, a).await; + get_ing_comments(t, a).await } else { let a = iq(t, &q.into()) .await? .into_iter() - .map(|x| x.into()) .collect::>(); - return get_ing_comments(t, a).await; + get_ing_comments(t, a).await } } From d18e7ca3c3d412d9832c0c1cea994138cccaed74 Mon Sep 17 00:00:00 2001 From: RocSun <710989028@qq.com> Date: Thu, 25 Jan 2024 00:03:11 +0800 Subject: [PATCH 10/10] fix:alway create private ing. --- src/args/cmd/ing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/args/cmd/ing.rs b/src/args/cmd/ing.rs index 6459a70..5305c23 100644 --- a/src/args/cmd/ing.rs +++ b/src/args/cmd/ing.rs @@ -78,7 +78,7 @@ pub struct CreateIng { pub content: String, /// 是否私有,默认是全站 - #[arg(short, long, default_value_t = true)] + #[arg(short, long, default_value_t = false)] pub private: bool, /// 是否发布为幸运