feat: complete in-game commands, GUIs, admin panel fixes, and launcher enhancements
This commit is contained in:
1 parent
a9ff92e1d1
commit
752f0cc43d
34 files changed
+4170
-181
No files matched your search
@@ -3,7 +3,7 @@
|
||||
use crate::auth::AuthUser;
|
||||
use crate::error::{AppError, AppResult};
|
||||
use crate::state::AppState;
|
||||
use axum::extract::{Path, State};
|
||||
use axum::extract::{Path, Query, State};
|
||||
use axum::Json;
|
||||
use scopenet_shared::{DirectMessage, FriendInfo, GameInvite, UserPost, UserProfileView};
|
||||
use serde::Deserialize;
|
||||
@@ -621,3 +621,72 @@ pub async fn like_user_post(
|
||||
|
||||
Ok(Json(serde_json::json!({ "ok": true })))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Members Search & Discovery
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SearchMembersQuery {
|
||||
pub q: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn search_members(
|
||||
auth: AuthUser,
|
||||
Query(query): Query<SearchMembersQuery>,
|
||||
State(state): State<AppState>,
|
||||
) -> AppResult<Json<Vec<scopenet_shared::MemberProfile>>> {
|
||||
let q = query.q.unwrap_or_default().trim().to_lowercase();
|
||||
let pattern = format!("%{q}%");
|
||||
|
||||
let rows: Vec<(String, String, String, String, Option<String>, Option<i64>, Option<String>, i64, Option<String>, Option<String>)> = sqlx::query_as(
|
||||
"SELECT u.uuid, u.username, u.role, u.status, u.skin_url,
|
||||
ul.global_level, ul.title, u.playtime_secs, u.last_seen_ingame,
|
||||
f.status as friendship_status
|
||||
FROM users u
|
||||
LEFT JOIN user_levels ul ON ul.uuid = u.uuid
|
||||
LEFT JOIN friendships f ON (f.user_uuid = ? AND f.friend_uuid = u.uuid)
|
||||
WHERE (? = '' OR LOWER(u.username) LIKE ?)
|
||||
ORDER BY (CASE WHEN LOWER(u.username) = ? THEN 1 ELSE 2 END), u.playtime_secs DESC
|
||||
LIMIT 60",
|
||||
)
|
||||
.bind(&auth.uuid)
|
||||
.bind(&q)
|
||||
.bind(&pattern)
|
||||
.bind(&q)
|
||||
.fetch_all(&state.db)
|
||||
.await?;
|
||||
|
||||
let now_ts = chrono::Utc::now().timestamp();
|
||||
|
||||
let list = rows
|
||||
.into_iter()
|
||||
.map(|(uuid, username, role, status, skin_url, glvl, title, playtime, last_seen, friend_status)| {
|
||||
let online = if let Some(ref ls) = last_seen {
|
||||
if let Ok(dt) = chrono::DateTime::parse_from_rfc3339(ls) {
|
||||
(now_ts - dt.timestamp()).abs() < 180
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let is_friend = friend_status.as_deref() == Some("accepted");
|
||||
scopenet_shared::MemberProfile {
|
||||
uuid,
|
||||
username,
|
||||
role,
|
||||
status,
|
||||
skin_url,
|
||||
global_level: glvl.unwrap_or(1),
|
||||
title,
|
||||
playtime_secs: playtime,
|
||||
last_seen,
|
||||
online,
|
||||
is_friend,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Json(list))
|
||||
}
|
||||
Reference in new issue
Block a user