Merge master into user play stats branch
Some checks failed
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-04-28 15:52:27 +08:00
80 changed files with 3609 additions and 434 deletions

View File

@@ -94,9 +94,10 @@ use crate::{
runtime_chat::stream_runtime_npc_chat_turn,
runtime_inventory::get_runtime_inventory_state,
runtime_profile::{
admin_disable_profile_redeem_code, admin_upsert_profile_redeem_code,
create_profile_recharge_order, get_profile_dashboard, get_profile_play_stats,
get_profile_recharge_center, get_profile_referral_invite_center, get_profile_wallet_ledger,
redeem_profile_referral_invite_code,
redeem_profile_referral_invite_code, redeem_profile_reward_code,
},
runtime_save::{
delete_runtime_snapshot, get_runtime_snapshot, list_profile_save_archives,
@@ -143,6 +144,20 @@ pub fn build_router(state: AppState) -> Router {
require_admin_auth,
)),
)
.route(
"/admin/api/profile/redeem-codes",
post(admin_upsert_profile_redeem_code).route_layer(middleware::from_fn_with_state(
state.clone(),
require_admin_auth,
)),
)
.route(
"/admin/api/profile/redeem-codes/disable",
post(admin_disable_profile_redeem_code).route_layer(middleware::from_fn_with_state(
state.clone(),
require_admin_auth,
)),
)
.route(
"/healthz",
get(|Extension(request_context): Extension<_>| async move {
@@ -581,6 +596,13 @@ pub fn build_router(state: AppState) -> Router {
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/works/{session_id}/play",
post(record_big_fish_play).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions",
post(create_puzzle_agent_session).route_layer(middleware::from_fn_with_state(
@@ -854,6 +876,20 @@ pub fn build_router(state: AppState) -> Router {
require_bearer_auth,
)),
)
.route(
"/api/runtime/profile/redeem-codes/redeem",
post(redeem_profile_reward_code).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/profile/redeem-codes/redeem",
post(redeem_profile_reward_code).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/profile/play-stats",
get(get_profile_play_stats).route_layer(middleware::from_fn_with_state(
@@ -1360,6 +1396,36 @@ mod tests {
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}
#[tokio::test]
async fn password_entry_dev_auto_register_creates_unknown_phone_when_enabled() {
let config = AppConfig {
dev_password_entry_auto_register_enabled: true,
..AppConfig::default()
};
let app = build_router(AppState::new(config).expect("state should build"));
let first_response =
password_login_request(app.clone(), "13800138023", TEST_PASSWORD).await;
let first_status = first_response.status();
let first_body = first_response
.into_body()
.collect()
.await
.expect("first response body should collect")
.to_bytes();
let first_payload: Value =
serde_json::from_slice(&first_body).expect("first response body should be valid json");
let second_response = password_login_request(app, "13800138023", TEST_PASSWORD).await;
assert_eq!(first_status, StatusCode::OK);
assert!(first_payload["token"].as_str().is_some());
assert_eq!(
first_payload["user"]["loginMethod"],
Value::String("password".to_string())
);
assert_eq!(second_response.status(), StatusCode::OK);
}
#[tokio::test]
async fn password_entry_logs_in_existing_phone_user_and_sets_refresh_cookie() {
let state = AppState::new(AppConfig::default()).expect("state should build");