删除后端未使用的历史 helper、mapper、handler 和 re-export 将仅测试使用的导入、常量和辅助函数收口到 cfg(test) 补齐 Jump Hop 测试构造体字段并对齐 Match3D 当前素材表测试契约 验证后端 workspace cargo check 与 Match3D、Puzzle 相关测试
150 lines
4.7 KiB
Rust
150 lines
4.7 KiB
Rust
use module_auth::AuthUser;
|
||
|
||
use crate::state::{AppState, PuzzleApiState};
|
||
|
||
pub const ORPHAN_WORK_OWNER_USER_ID: &str = "wx-openid-placeholder";
|
||
pub const ORPHAN_WORK_AUTHOR_DISPLAY_NAME: &str = "失效作者";
|
||
pub const ORPHAN_WORK_AUTHOR_PUBLIC_USER_CODE: &str = "SY-00000000";
|
||
|
||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||
pub struct WorkAuthorSummary {
|
||
pub display_name: String,
|
||
pub public_user_code: Option<String>,
|
||
}
|
||
|
||
/// 中文注释:作品作者的真相源是 owner_user_id;历史昵称字段只作为账号资料不可读时的兼容回退。
|
||
pub fn resolve_work_author_by_user_id(
|
||
state: &AppState,
|
||
owner_user_id: &str,
|
||
fallback_display_name: Option<&str>,
|
||
fallback_public_user_code: Option<&str>,
|
||
) -> WorkAuthorSummary {
|
||
resolve_work_author_by_user_id_with_service(
|
||
state.auth_user_service(),
|
||
owner_user_id,
|
||
fallback_display_name,
|
||
fallback_public_user_code,
|
||
)
|
||
}
|
||
|
||
pub fn resolve_puzzle_work_author_by_user_id(
|
||
state: &PuzzleApiState,
|
||
owner_user_id: &str,
|
||
fallback_display_name: Option<&str>,
|
||
fallback_public_user_code: Option<&str>,
|
||
) -> WorkAuthorSummary {
|
||
resolve_work_author_by_user_id_with_service(
|
||
state.auth_user_service(),
|
||
owner_user_id,
|
||
fallback_display_name,
|
||
fallback_public_user_code,
|
||
)
|
||
}
|
||
|
||
fn resolve_work_author_by_user_id_with_service(
|
||
auth_user_service: &module_auth::AuthUserService,
|
||
owner_user_id: &str,
|
||
fallback_display_name: Option<&str>,
|
||
fallback_public_user_code: Option<&str>,
|
||
) -> WorkAuthorSummary {
|
||
let fallback_display_name =
|
||
normalize_optional_text(fallback_display_name).unwrap_or_else(|| "玩家".to_string());
|
||
let _fallback_public_user_code = normalize_optional_text(fallback_public_user_code);
|
||
|
||
let Some(owner_user_id) = normalize_optional_text(Some(owner_user_id)) else {
|
||
return orphan_work_author_summary();
|
||
};
|
||
|
||
match auth_user_service.get_user_by_id(&owner_user_id) {
|
||
Ok(Some(user)) => map_auth_user_to_work_author_summary(user, fallback_display_name),
|
||
Ok(None) | Err(_) => orphan_work_author_summary(),
|
||
}
|
||
}
|
||
|
||
fn map_auth_user_to_work_author_summary(
|
||
user: AuthUser,
|
||
fallback_display_name: String,
|
||
) -> WorkAuthorSummary {
|
||
WorkAuthorSummary {
|
||
display_name: normalize_optional_text(Some(user.display_name.as_str()))
|
||
.unwrap_or(fallback_display_name),
|
||
public_user_code: normalize_optional_text(Some(user.public_user_code.as_str())),
|
||
}
|
||
}
|
||
|
||
fn normalize_optional_text(value: Option<&str>) -> Option<String> {
|
||
value
|
||
.map(str::trim)
|
||
.filter(|value| !value.is_empty())
|
||
.map(ToOwned::to_owned)
|
||
}
|
||
|
||
fn orphan_work_author_summary() -> WorkAuthorSummary {
|
||
WorkAuthorSummary {
|
||
display_name: ORPHAN_WORK_AUTHOR_DISPLAY_NAME.to_string(),
|
||
public_user_code: Some(ORPHAN_WORK_AUTHOR_PUBLIC_USER_CODE.to_string()),
|
||
}
|
||
}
|
||
|
||
/// 中文注释:运维回填只处理空作者或认证仓储不可再解析的历史 owner_user_id,避免把有效作品误转给占位账号。
|
||
#[cfg(test)]
|
||
pub fn should_rebind_orphan_work_owner(
|
||
auth_user_service: &module_auth::AuthUserService,
|
||
owner_user_id: &str,
|
||
) -> bool {
|
||
let Some(owner_user_id) = normalize_optional_text(Some(owner_user_id)) else {
|
||
return true;
|
||
};
|
||
if owner_user_id == ORPHAN_WORK_OWNER_USER_ID {
|
||
return false;
|
||
}
|
||
|
||
!matches!(
|
||
auth_user_service.get_user_by_id(&owner_user_id),
|
||
Ok(Some(_))
|
||
)
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use module_auth::{AuthUserService, InMemoryAuthStore};
|
||
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn orphan_work_author_summary_uses_placeholder_account() {
|
||
assert_eq!(
|
||
orphan_work_author_summary(),
|
||
WorkAuthorSummary {
|
||
display_name: "失效作者".to_string(),
|
||
public_user_code: Some("SY-00000000".to_string()),
|
||
}
|
||
);
|
||
}
|
||
|
||
#[test]
|
||
fn missing_author_resolves_to_placeholder_account() {
|
||
let service = AuthUserService::new(InMemoryAuthStore::default());
|
||
|
||
let author = resolve_work_author_by_user_id_with_service(
|
||
&service,
|
||
"user_missing",
|
||
Some("历史昵称"),
|
||
Some("SY-00000001"),
|
||
);
|
||
|
||
assert_eq!(author, orphan_work_author_summary());
|
||
}
|
||
#[test]
|
||
fn should_rebind_orphan_work_owner_detects_missing_and_empty_author() {
|
||
let service = AuthUserService::new(InMemoryAuthStore::default());
|
||
|
||
assert!(should_rebind_orphan_work_owner(&service, ""));
|
||
assert!(should_rebind_orphan_work_owner(&service, "user_missing"));
|
||
assert!(!should_rebind_orphan_work_owner(
|
||
&service,
|
||
ORPHAN_WORK_OWNER_USER_ID
|
||
));
|
||
}
|
||
}
|