mirror of
https://git.ethanthesleepy.one/ethanaobrien/ew
synced 2026-08-26 23:12:20 +08:00
Render clearrates for private songs for that user
This commit is contained in:
@@ -251,6 +251,14 @@ pub fn non_public_music_ids() -> JsonValue {
|
||||
DATABASE.lock_and_select_all("SELECT music_id FROM songs WHERE visibility!='public' ORDER BY music_id", params!()).unwrap_or(array![])
|
||||
}
|
||||
|
||||
pub fn non_public_music_ids_for(user_id: i64) -> JsonValue {
|
||||
DATABASE.lock_and_select_all("
|
||||
SELECT music_id FROM songs
|
||||
WHERE visibility!='public' AND owner_id!=?1
|
||||
AND music_id NOT IN (SELECT music_id FROM shared_users WHERE user_id=?1)
|
||||
ORDER BY music_id", params!(user_id)).unwrap_or(array![])
|
||||
}
|
||||
|
||||
// Which of these candidate ids no longer exist in the catalog. Only the custom
|
||||
// range is ever considered, so official songs can't come back from this. A song
|
||||
// that's merely private/shared still has its row - only genuinely deleted ids
|
||||
|
||||
@@ -188,13 +188,9 @@ fn get_pass_percent(failed: i64, pass: i64) -> String {
|
||||
|
||||
fn get_json() -> JsonValue {
|
||||
let lives = DATABASE.lock_and_select_all("SELECT live_id FROM lives", params!()).unwrap();
|
||||
let hidden = crate::router::custom_song::hidden_live_ids();
|
||||
let mut rates = array![];
|
||||
let mut ids = array![];
|
||||
for id in lives.members() {
|
||||
if hidden.contains(id.as_i64().unwrap()) {
|
||||
continue;
|
||||
}
|
||||
let info = DATABASE.get_live_data(id.as_i64().unwrap());
|
||||
if info.is_err() {
|
||||
continue;
|
||||
@@ -239,7 +235,24 @@ async fn get_clearrate_json() -> JsonValue {
|
||||
}
|
||||
|
||||
pub async fn clearrate(req: HttpRequest) -> impl Responder {
|
||||
global::api(&req, Some(get_clearrate_json().await))
|
||||
let mut data = get_clearrate_json().await;
|
||||
let hidden = crate::router::custom_song::hidden_live_ids_for_user(global::get_uid(req.headers()));
|
||||
if !hidden.is_empty() {
|
||||
let rates = data["all_user_clear_rate"].clone();
|
||||
let ids = data["master_music_ids"].clone();
|
||||
let mut new_rates = array![];
|
||||
let mut new_ids = array![];
|
||||
for (i, rate) in rates.members().enumerate() {
|
||||
if hidden.contains(rate["master_live_id"].as_i64().unwrap()) {
|
||||
continue;
|
||||
}
|
||||
new_rates.push(rate.clone()).unwrap();
|
||||
new_ids.push(ids[i].clone()).unwrap();
|
||||
}
|
||||
data["all_user_clear_rate"] = new_rates;
|
||||
data["master_music_ids"] = new_ids;
|
||||
}
|
||||
global::api(&req, Some(data))
|
||||
}
|
||||
|
||||
pub async fn ranking(req: HttpRequest, body: String) -> impl Responder {
|
||||
|
||||
@@ -120,6 +120,13 @@ pub fn hidden_live_ids() -> JsonValue {
|
||||
database::non_public_music_ids()
|
||||
}
|
||||
|
||||
pub fn hidden_live_ids_for_user(uid: i64) -> JsonValue {
|
||||
if disabled() {
|
||||
return array![];
|
||||
}
|
||||
database::non_public_music_ids_for(uid)
|
||||
}
|
||||
|
||||
fn song_path(music_id: i64, file: &str) -> String {
|
||||
get_data_path(&format!("custom_songs/{}/{}", music_id, file))
|
||||
}
|
||||
@@ -1464,4 +1471,61 @@ mod tests {
|
||||
assert_eq!(call(&chart_md5, "json").status(), actix_web::http::StatusCode::NOT_FOUND);
|
||||
assert_eq!(call(&new_md5, "json").status(), actix_web::http::StatusCode::OK);
|
||||
}
|
||||
|
||||
// The JSON clear-rate endpoint filters non-public custom songs per requesting
|
||||
// user: the owner sees all of theirs, a shared user sees the songs shared with
|
||||
// them, everyone else sees only public ones. Official (stock) live ids are
|
||||
// always visible. The parallel master_music_ids array must stay index-aligned
|
||||
// with all_user_clear_rate after filtering.
|
||||
#[test]
|
||||
fn clearrate_hides_custom_songs_per_user() {
|
||||
use actix_web::{test::TestRequest, Responder};
|
||||
use crate::router::clear_rate;
|
||||
let _lock = crate::runtime::lock_test_data_path();
|
||||
crate::runtime::set_enable_custom_songs(true);
|
||||
|
||||
let owner = 5001;
|
||||
let shared_user = 5002;
|
||||
let outsider = 5003;
|
||||
|
||||
let public_id = database::next_music_id();
|
||||
database::insert_song(public_id, owner, &object!{music_id: public_id}, "public", &array![], false);
|
||||
let private_id = database::next_music_id();
|
||||
database::insert_song(private_id, owner, &object!{music_id: private_id}, "private", &array![], false);
|
||||
let shared_id = database::next_music_id();
|
||||
database::insert_song(shared_id, owner, &object!{music_id: shared_id}, "shared", &array![shared_user], false);
|
||||
// A stock live id, outside the custom range - never filtered
|
||||
let stock_id: i64 = 1_500_123;
|
||||
|
||||
for id in [public_id, private_id, shared_id, stock_id] {
|
||||
clear_rate::live_completed(id, 1, false, 100, owner);
|
||||
}
|
||||
clear_rate::invalidate_cache();
|
||||
|
||||
// master_live_ids the endpoint serves to this uid, with an index-alignment guard
|
||||
let visible_to = |uid: i64| -> Vec<i64> {
|
||||
let req = TestRequest::default().insert_header(("aoharu-user-id", uid.to_string())).to_http_request();
|
||||
let body = actix_web::rt::System::new().block_on(async {
|
||||
let resp = clear_rate::clearrate(req.clone()).await.respond_to(&req).map_into_boxed_body();
|
||||
actix_web::body::to_bytes(resp.into_body()).await.unwrap()
|
||||
});
|
||||
let json = jzon::parse(&crate::encryption::decrypt_packet(&String::from_utf8_lossy(&body)).unwrap()).unwrap();
|
||||
let rates = &json["data"]["all_user_clear_rate"];
|
||||
let ids = &json["data"]["master_music_ids"];
|
||||
assert_eq!(rates.len(), ids.len(), "parallel arrays must stay aligned for uid {}", uid);
|
||||
rates.members().map(|r| r["master_live_id"].as_i64().unwrap()).collect()
|
||||
};
|
||||
let sees = |uid: i64, id: i64| visible_to(uid).contains(&id);
|
||||
|
||||
// Owner sees every song of theirs plus the stock id
|
||||
assert!(sees(owner, public_id) && sees(owner, private_id) && sees(owner, shared_id) && sees(owner, stock_id));
|
||||
// Shared user sees public + shared + stock, never the private one
|
||||
assert!(sees(shared_user, public_id) && sees(shared_user, shared_id) && sees(shared_user, stock_id));
|
||||
assert!(!sees(shared_user, private_id));
|
||||
// Outsider and anonymous (uid 0) see public + stock only
|
||||
for uid in [outsider, 0] {
|
||||
assert!(sees(uid, public_id) && sees(uid, stock_id));
|
||||
assert!(!sees(uid, private_id) && !sees(uid, shared_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,7 +855,7 @@ mod tests {
|
||||
|
||||
assert_eq!(asset_gate(current, "Windows", ""), None);
|
||||
assert_eq!(asset_gate(current, "android", ""), None);
|
||||
assert_eq!(asset_gate(current, "ios", ""), Some(global::RESULT_GAME_VERSION_UPDATED));
|
||||
assert_eq!(asset_gate(current, "ios", ""), None);
|
||||
|
||||
assert_eq!(asset_gate(stock, "android", ""), None);
|
||||
assert_eq!(asset_gate(stock, "ios", ""), None);
|
||||
|
||||
Reference in New Issue
Block a user