fix: fix some issues

This commit is contained in:
master 2025-05-04 03:59:59 +08:00
parent 3fe0538468
commit f245a68790
13 changed files with 99 additions and 36 deletions

View File

@ -2,12 +2,11 @@ use std::{fmt::Debug, ops::Deref, sync::Arc};
use fetch::{HttpClient, HttpClientTrait};
use maplit::hashmap;
use sea_orm::DbErr;
use serde::{Deserialize, Serialize};
use sea_orm::{ActiveModelTrait, ActiveValue::Set, DbErr, TryIntoModel};
use url::Url;
use util::OptDynErr;
use super::{MikanConfig, constants::MIKAN_ACCOUNT_MANAGE_PAGE_PATH};
use super::{MikanConfig, MikanCredentialForm, constants::MIKAN_ACCOUNT_MANAGE_PAGE_PATH};
use crate::{
app::AppContextTrait,
crypto::UserPassCredential,
@ -15,22 +14,6 @@ use crate::{
extract::mikan::constants::{MIKAN_LOGIN_PAGE_PATH, MIKAN_LOGIN_PAGE_SEARCH},
models::credential_3rd::{self, Credential3rdType},
};
#[derive(Default, Clone, Deserialize, Serialize)]
pub struct MikanCredentialForm {
pub password: String,
pub username: String,
pub user_agent: String,
}
impl Debug for MikanCredentialForm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MikanCredentialForm")
.field("username", &String::from("[secrecy]"))
.field("password", &String::from("[secrecy]"))
.field("user_agent", &String::from("[secrecy]"))
.finish()
}
}
#[derive(Debug)]
pub struct MikanClient {
@ -154,6 +137,28 @@ impl MikanClient {
}
}
pub async fn save_credential(
&self,
ctx: Arc<dyn AppContextTrait>,
subscriber_id: i32,
credential_form: MikanCredentialForm,
) -> RecorderResult<credential_3rd::Model> {
let db = ctx.db();
let am = credential_3rd::ActiveModel {
username: Set(Some(credential_form.username)),
password: Set(Some(credential_form.password)),
user_agent: Set(Some(credential_form.user_agent)),
credential_type: Set(Credential3rdType::Mikan),
subscriber_id: Set(subscriber_id),
..Default::default()
}
.try_encrypt(ctx.clone())
.await?;
let credential: credential_3rd::Model = am.save(db).await?.try_into_model()?;
Ok(credential)
}
pub async fn fork_with_credential(
&self,
ctx: Arc<dyn AppContextTrait>,

View File

@ -0,0 +1,20 @@
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
#[derive(Default, Clone, Deserialize, Serialize)]
pub struct MikanCredentialForm {
pub password: String,
pub username: String,
pub user_agent: String,
}
impl Debug for MikanCredentialForm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MikanCredentialForm")
.field("username", &String::from("[secrecy]"))
.field("password", &String::from("[secrecy]"))
.field("user_agent", &String::from("[secrecy]"))
.finish()
}
}

View File

@ -1,15 +1,17 @@
mod client;
mod config;
mod constants;
mod credential;
mod rss;
mod web;
pub use client::{MikanClient, MikanCredentialForm};
pub use client::MikanClient;
pub use config::MikanConfig;
pub use constants::{
MIKAN_ACCOUNT_MANAGE_PAGE_PATH, MIKAN_LOGIN_PAGE_PATH, MIKAN_LOGIN_PAGE_SEARCH,
MIKAN_POSTER_BUCKET_KEY, MIKAN_UNKNOWN_FANSUB_ID, MIKAN_UNKNOWN_FANSUB_NAME,
};
pub use credential::MikanCredentialForm;
pub use rss::{
MikanBangumiIndexRssChannel, MikanBangumiRssChannel, MikanBangumiRssUrlMeta, MikanRssChannel,
MikanRssItem, MikanSubscriberAggregationRssUrlMeta, MikanSubscriberStreamRssChannel,

View File

@ -704,21 +704,25 @@ mod test {
#![allow(unused_variables)]
use std::fs;
use fetch::get_random_ua;
use rstest::{fixture, rstest};
use tracing::Level;
use url::Url;
use zune_image::{codecs::ImageFormat, image::Image};
use super::*;
use crate::test_utils::{
app::UnitTestAppContext, database::build_testing_database_service,
mikan::build_testing_mikan_client, storage::build_testing_storage_service,
tracing::try_init_testing_tracing,
use crate::{
extract::mikan::MikanCredentialForm,
test_utils::{
app::UnitTestAppContext, crypto::build_testing_crypto_service,
database::build_testing_database_service, mikan::build_testing_mikan_client,
storage::build_testing_storage_service, tracing::try_init_testing_tracing,
},
};
#[fixture]
fn before_each() {
try_init_testing_tracing(Level::INFO);
try_init_testing_tracing(Level::DEBUG);
}
#[rstest]
@ -853,7 +857,7 @@ mod test {
#[rstest]
#[test]
fn ttest_extract_mikan_bangumi_meta_from_expand_subscribed_fragment(
fn test_extract_mikan_bangumi_meta_from_expand_subscribed_fragment(
before_each: (),
) -> RecorderResult<()> {
let origin_poster_src =
@ -934,9 +938,11 @@ mod test {
let app_ctx = {
let mikan_client = build_testing_mikan_client(mikan_base_url.clone()).await?;
let db_service = build_testing_database_service().await?;
let crypto_service = build_testing_crypto_service().await?;
let app_ctx = UnitTestAppContext::builder()
.mikan(mikan_client)
.db(db_service)
.crypto(crypto_service)
.build();
Arc::new(app_ctx)
@ -944,6 +950,18 @@ mod test {
let mikan_client = app_ctx.mikan();
let credential = mikan_client
.save_credential(
app_ctx.clone(),
1,
MikanCredentialForm {
username: String::from("test_username"),
password: String::from("test_password"),
user_agent: get_random_ua().to_string(),
},
)
.await?;
let mikan_season_flow_url =
build_mikan_season_flow_url(mikan_base_url, 2025, MikanSeasonStr::Spring);
@ -951,7 +969,7 @@ mod test {
mikan_client,
app_ctx.clone(),
mikan_season_flow_url,
1,
credential.id,
)
.await?;

View File

@ -24,7 +24,7 @@ pub enum Credential3rdType {
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)]
#[sea_orm(table_name = "credential_3rd")]
#[sea_orm(table_name = "credential3rd")]
pub struct Model {
#[sea_orm(default_expr = "Expr::current_timestamp()")]
pub created_at: DateTimeUtc,

View File

@ -0,0 +1,9 @@
use crate::{
crypto::{CryptoConfig, CryptoService},
errors::RecorderResult,
};
pub async fn build_testing_crypto_service() -> RecorderResult<CryptoService> {
let crypto = CryptoService::from_config(CryptoConfig {}).await?;
Ok(crypto)
}

View File

@ -5,7 +5,7 @@ use crate::{
#[cfg(feature = "testcontainers")]
pub async fn build_testing_database_service() -> RecorderResult<DatabaseService> {
use testcontainers::runners::AsyncRunner;
use testcontainers::{ImageExt, runners::AsyncRunner};
use testcontainers_ext::{ImageDefaultLogConsumerExt, ImagePruneExistedLabelExt};
use testcontainers_modules::postgres::Postgres;
@ -13,6 +13,7 @@ pub async fn build_testing_database_service() -> RecorderResult<DatabaseService>
.with_db_name("konobangu")
.with_user("konobangu")
.with_password("konobangu")
.with_tag("17-alpine")
.with_default_log_consumer()
.with_prune_existed_label(env!("CARGO_PKG_NAME"), "postgres", true, true)
.await?;

View File

@ -1,4 +1,5 @@
pub mod app;
pub mod crypto;
pub mod database;
pub mod mikan;
pub mod storage;

View File

@ -5,6 +5,7 @@ pub fn try_init_testing_tracing(level: Level) {
let crate_name = env!("CARGO_PKG_NAME");
let level = level.as_str().to_lowercase();
let filter = EnvFilter::new(format!("{crate_name}[]={level}"))
.add_directive(format!("mockito[]={level}").parse().unwrap());
.add_directive(format!("mockito[]={level}").parse().unwrap())
.add_directive(format!("sqlx[]={level}").parse().unwrap());
let _ = tracing_subscriber::fmt().with_env_filter(filter).try_init();
}

View File

@ -2,7 +2,13 @@ set windows-shell := ["pwsh.exe", "-c"]
set dotenv-load := true
prepare-dev-recorder:
cargo install sea-orm-cli watchexec cargo-llvm-cov cargo-nextest
cargo install sea-orm-cli cargo-llvm-cov cargo-nextest
# install watchexec
prepare-dev-testcontainers:
docker pull linuxserver/qbittorrent:latest
docker pull ghcr.io/dumtruck/konobangu-testing-torrents:latest
docker pull postgres:17-alpine
dev-webui:
pnpm run --filter=webui dev

View File

@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use snafu::Snafu;
use crate::get_random_mobile_ua;
use crate::get_random_ua;
pub struct RateLimiterMiddleware {
rate_limiter: RateLimiter,
@ -176,7 +176,7 @@ impl HttpClient {
config
.user_agent
.as_deref()
.unwrap_or_else(|| get_random_mobile_ua()),
.unwrap_or_else(|| get_random_ua()),
);
#[cfg(not(target_arch = "wasm32"))]
@ -291,7 +291,7 @@ impl HttpClient {
self.config
.user_agent
.as_deref()
.unwrap_or_else(|| get_random_mobile_ua()),
.unwrap_or_else(|| get_random_ua()),
);
#[cfg(not(target_arch = "wasm32"))]

View File

@ -5,7 +5,7 @@ lazy_static! {
serde_json::from_str::<Vec<String>>(include_str!("./ua.json")).unwrap();
}
pub fn get_random_mobile_ua() -> &'static str {
pub fn get_random_ua() -> &'static str {
DEFAULT_HTTP_CLIENT_USER_AGENT[fastrand::usize(0..DEFAULT_HTTP_CLIENT_USER_AGENT.len())]
.as_str()
}

View File

@ -6,7 +6,7 @@ pub mod html;
pub mod image;
pub mod test_util;
pub use core::get_random_mobile_ua;
pub use core::get_random_ua;
pub use bytes::fetch_bytes;
pub use client::{HttpClient, HttpClientConfig, HttpClientError, HttpClientTrait};