fix: fix some issues
This commit is contained in:
parent
3fe0538468
commit
f245a68790
@ -2,12 +2,11 @@ use std::{fmt::Debug, ops::Deref, sync::Arc};
|
|||||||
|
|
||||||
use fetch::{HttpClient, HttpClientTrait};
|
use fetch::{HttpClient, HttpClientTrait};
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use sea_orm::DbErr;
|
use sea_orm::{ActiveModelTrait, ActiveValue::Set, DbErr, TryIntoModel};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use util::OptDynErr;
|
use util::OptDynErr;
|
||||||
|
|
||||||
use super::{MikanConfig, constants::MIKAN_ACCOUNT_MANAGE_PAGE_PATH};
|
use super::{MikanConfig, MikanCredentialForm, constants::MIKAN_ACCOUNT_MANAGE_PAGE_PATH};
|
||||||
use crate::{
|
use crate::{
|
||||||
app::AppContextTrait,
|
app::AppContextTrait,
|
||||||
crypto::UserPassCredential,
|
crypto::UserPassCredential,
|
||||||
@ -15,22 +14,6 @@ use crate::{
|
|||||||
extract::mikan::constants::{MIKAN_LOGIN_PAGE_PATH, MIKAN_LOGIN_PAGE_SEARCH},
|
extract::mikan::constants::{MIKAN_LOGIN_PAGE_PATH, MIKAN_LOGIN_PAGE_SEARCH},
|
||||||
models::credential_3rd::{self, Credential3rdType},
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct MikanClient {
|
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(
|
pub async fn fork_with_credential(
|
||||||
&self,
|
&self,
|
||||||
ctx: Arc<dyn AppContextTrait>,
|
ctx: Arc<dyn AppContextTrait>,
|
||||||
|
20
apps/recorder/src/extract/mikan/credential.rs
Normal file
20
apps/recorder/src/extract/mikan/credential.rs
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,17 @@
|
|||||||
mod client;
|
mod client;
|
||||||
mod config;
|
mod config;
|
||||||
mod constants;
|
mod constants;
|
||||||
|
mod credential;
|
||||||
mod rss;
|
mod rss;
|
||||||
mod web;
|
mod web;
|
||||||
|
|
||||||
pub use client::{MikanClient, MikanCredentialForm};
|
pub use client::MikanClient;
|
||||||
pub use config::MikanConfig;
|
pub use config::MikanConfig;
|
||||||
pub use constants::{
|
pub use constants::{
|
||||||
MIKAN_ACCOUNT_MANAGE_PAGE_PATH, MIKAN_LOGIN_PAGE_PATH, MIKAN_LOGIN_PAGE_SEARCH,
|
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,
|
MIKAN_POSTER_BUCKET_KEY, MIKAN_UNKNOWN_FANSUB_ID, MIKAN_UNKNOWN_FANSUB_NAME,
|
||||||
};
|
};
|
||||||
|
pub use credential::MikanCredentialForm;
|
||||||
pub use rss::{
|
pub use rss::{
|
||||||
MikanBangumiIndexRssChannel, MikanBangumiRssChannel, MikanBangumiRssUrlMeta, MikanRssChannel,
|
MikanBangumiIndexRssChannel, MikanBangumiRssChannel, MikanBangumiRssUrlMeta, MikanRssChannel,
|
||||||
MikanRssItem, MikanSubscriberAggregationRssUrlMeta, MikanSubscriberStreamRssChannel,
|
MikanRssItem, MikanSubscriberAggregationRssUrlMeta, MikanSubscriberStreamRssChannel,
|
||||||
|
@ -704,21 +704,25 @@ mod test {
|
|||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
use fetch::get_random_ua;
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use zune_image::{codecs::ImageFormat, image::Image};
|
use zune_image::{codecs::ImageFormat, image::Image};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::test_utils::{
|
use crate::{
|
||||||
app::UnitTestAppContext, database::build_testing_database_service,
|
extract::mikan::MikanCredentialForm,
|
||||||
mikan::build_testing_mikan_client, storage::build_testing_storage_service,
|
test_utils::{
|
||||||
tracing::try_init_testing_tracing,
|
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]
|
#[fixture]
|
||||||
fn before_each() {
|
fn before_each() {
|
||||||
try_init_testing_tracing(Level::INFO);
|
try_init_testing_tracing(Level::DEBUG);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@ -853,7 +857,7 @@ mod test {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[test]
|
#[test]
|
||||||
fn ttest_extract_mikan_bangumi_meta_from_expand_subscribed_fragment(
|
fn test_extract_mikan_bangumi_meta_from_expand_subscribed_fragment(
|
||||||
before_each: (),
|
before_each: (),
|
||||||
) -> RecorderResult<()> {
|
) -> RecorderResult<()> {
|
||||||
let origin_poster_src =
|
let origin_poster_src =
|
||||||
@ -934,9 +938,11 @@ mod test {
|
|||||||
let app_ctx = {
|
let app_ctx = {
|
||||||
let mikan_client = build_testing_mikan_client(mikan_base_url.clone()).await?;
|
let mikan_client = build_testing_mikan_client(mikan_base_url.clone()).await?;
|
||||||
let db_service = build_testing_database_service().await?;
|
let db_service = build_testing_database_service().await?;
|
||||||
|
let crypto_service = build_testing_crypto_service().await?;
|
||||||
let app_ctx = UnitTestAppContext::builder()
|
let app_ctx = UnitTestAppContext::builder()
|
||||||
.mikan(mikan_client)
|
.mikan(mikan_client)
|
||||||
.db(db_service)
|
.db(db_service)
|
||||||
|
.crypto(crypto_service)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Arc::new(app_ctx)
|
Arc::new(app_ctx)
|
||||||
@ -944,6 +950,18 @@ mod test {
|
|||||||
|
|
||||||
let mikan_client = app_ctx.mikan();
|
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 =
|
let mikan_season_flow_url =
|
||||||
build_mikan_season_flow_url(mikan_base_url, 2025, MikanSeasonStr::Spring);
|
build_mikan_season_flow_url(mikan_base_url, 2025, MikanSeasonStr::Spring);
|
||||||
|
|
||||||
@ -951,7 +969,7 @@ mod test {
|
|||||||
mikan_client,
|
mikan_client,
|
||||||
app_ctx.clone(),
|
app_ctx.clone(),
|
||||||
mikan_season_flow_url,
|
mikan_season_flow_url,
|
||||||
1,
|
credential.id,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub enum Credential3rdType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, DeriveEntityModel)]
|
||||||
#[sea_orm(table_name = "credential_3rd")]
|
#[sea_orm(table_name = "credential3rd")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(default_expr = "Expr::current_timestamp()")]
|
#[sea_orm(default_expr = "Expr::current_timestamp()")]
|
||||||
pub created_at: DateTimeUtc,
|
pub created_at: DateTimeUtc,
|
||||||
|
9
apps/recorder/src/test_utils/crypto.rs
Normal file
9
apps/recorder/src/test_utils/crypto.rs
Normal 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)
|
||||||
|
}
|
@ -5,7 +5,7 @@ use crate::{
|
|||||||
|
|
||||||
#[cfg(feature = "testcontainers")]
|
#[cfg(feature = "testcontainers")]
|
||||||
pub async fn build_testing_database_service() -> RecorderResult<DatabaseService> {
|
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_ext::{ImageDefaultLogConsumerExt, ImagePruneExistedLabelExt};
|
||||||
use testcontainers_modules::postgres::Postgres;
|
use testcontainers_modules::postgres::Postgres;
|
||||||
|
|
||||||
@ -13,6 +13,7 @@ pub async fn build_testing_database_service() -> RecorderResult<DatabaseService>
|
|||||||
.with_db_name("konobangu")
|
.with_db_name("konobangu")
|
||||||
.with_user("konobangu")
|
.with_user("konobangu")
|
||||||
.with_password("konobangu")
|
.with_password("konobangu")
|
||||||
|
.with_tag("17-alpine")
|
||||||
.with_default_log_consumer()
|
.with_default_log_consumer()
|
||||||
.with_prune_existed_label(env!("CARGO_PKG_NAME"), "postgres", true, true)
|
.with_prune_existed_label(env!("CARGO_PKG_NAME"), "postgres", true, true)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
|
pub mod crypto;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
pub mod mikan;
|
pub mod mikan;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
@ -5,6 +5,7 @@ pub fn try_init_testing_tracing(level: Level) {
|
|||||||
let crate_name = env!("CARGO_PKG_NAME");
|
let crate_name = env!("CARGO_PKG_NAME");
|
||||||
let level = level.as_str().to_lowercase();
|
let level = level.as_str().to_lowercase();
|
||||||
let filter = EnvFilter::new(format!("{crate_name}[]={level}"))
|
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();
|
let _ = tracing_subscriber::fmt().with_env_filter(filter).try_init();
|
||||||
}
|
}
|
||||||
|
8
justfile
8
justfile
@ -2,7 +2,13 @@ set windows-shell := ["pwsh.exe", "-c"]
|
|||||||
set dotenv-load := true
|
set dotenv-load := true
|
||||||
|
|
||||||
prepare-dev-recorder:
|
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:
|
dev-webui:
|
||||||
pnpm run --filter=webui dev
|
pnpm run --filter=webui dev
|
||||||
|
@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use serde_with::serde_as;
|
use serde_with::serde_as;
|
||||||
use snafu::Snafu;
|
use snafu::Snafu;
|
||||||
|
|
||||||
use crate::get_random_mobile_ua;
|
use crate::get_random_ua;
|
||||||
|
|
||||||
pub struct RateLimiterMiddleware {
|
pub struct RateLimiterMiddleware {
|
||||||
rate_limiter: RateLimiter,
|
rate_limiter: RateLimiter,
|
||||||
@ -176,7 +176,7 @@ impl HttpClient {
|
|||||||
config
|
config
|
||||||
.user_agent
|
.user_agent
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or_else(|| get_random_mobile_ua()),
|
.unwrap_or_else(|| get_random_ua()),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
@ -291,7 +291,7 @@ impl HttpClient {
|
|||||||
self.config
|
self.config
|
||||||
.user_agent
|
.user_agent
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or_else(|| get_random_mobile_ua()),
|
.unwrap_or_else(|| get_random_ua()),
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
@ -5,7 +5,7 @@ lazy_static! {
|
|||||||
serde_json::from_str::<Vec<String>>(include_str!("./ua.json")).unwrap();
|
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())]
|
DEFAULT_HTTP_CLIENT_USER_AGENT[fastrand::usize(0..DEFAULT_HTTP_CLIENT_USER_AGENT.len())]
|
||||||
.as_str()
|
.as_str()
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ pub mod html;
|
|||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod test_util;
|
pub mod test_util;
|
||||||
|
|
||||||
pub use core::get_random_mobile_ua;
|
pub use core::get_random_ua;
|
||||||
|
|
||||||
pub use bytes::fetch_bytes;
|
pub use bytes::fetch_bytes;
|
||||||
pub use client::{HttpClient, HttpClientConfig, HttpClientError, HttpClientTrait};
|
pub use client::{HttpClient, HttpClientConfig, HttpClientError, HttpClientTrait};
|
||||||
|
Loading…
Reference in New Issue
Block a user