Now we have a concept of an avatar at the server, realm, and scene level
and we have the groundwork for a realm store. New uesrs no longer props,
they get a default avatar. New system supports gender
{male,female,neutral} and {child,adult}.
98 lines
3.9 KiB
Rust
98 lines
3.9 KiB
Rust
//! API routes for user UI.
|
|
//!
|
|
//! This router provides READ-ONLY access to realms, scenes, and spots.
|
|
//! All create/update/delete operations are handled by the admin-ui.
|
|
//! Channel presence is handled via WebSocket.
|
|
|
|
use axum::{Router, routing::get};
|
|
|
|
use super::{auth, avatars, inventory, realms, scenes, websocket};
|
|
use crate::app::AppState;
|
|
|
|
/// Build the API router for user UI.
|
|
///
|
|
/// Note: This router is READ-ONLY for realms/scenes/spots.
|
|
/// Auth routes (login, logout, signup, join-realm) are allowed.
|
|
/// Channel presence (join, leave, position, emotion, members) is handled via WebSocket.
|
|
pub fn api_router() -> Router<AppState> {
|
|
Router::new()
|
|
// Auth routes (these are user-facing operations)
|
|
.route("/auth/me", get(auth::get_current_user))
|
|
.route("/auth/login", axum::routing::post(auth::login))
|
|
.route("/auth/logout", axum::routing::post(auth::logout))
|
|
.route("/auth/signup", axum::routing::post(auth::signup))
|
|
.route("/auth/guest", axum::routing::post(auth::guest_login))
|
|
.route("/auth/join-realm", axum::routing::post(auth::join_realm))
|
|
.route(
|
|
"/auth/reset-password",
|
|
axum::routing::post(auth::reset_password),
|
|
)
|
|
.route(
|
|
"/auth/register-guest",
|
|
axum::routing::post(auth::register_guest),
|
|
)
|
|
.route(
|
|
"/auth/preferences",
|
|
axum::routing::put(auth::update_preferences),
|
|
)
|
|
// Realm routes (READ-ONLY)
|
|
.route("/realms", get(realms::list_realms))
|
|
.route("/realms/{slug}", get(realms::get_realm))
|
|
.route(
|
|
"/realms/{slug}/available",
|
|
get(realms::check_slug_available),
|
|
)
|
|
// Scene routes (READ-ONLY)
|
|
.route("/realms/{slug}/entry-scene", get(scenes::get_entry_scene))
|
|
.route("/realms/{slug}/scenes", get(scenes::list_scenes))
|
|
.route("/realms/{slug}/scenes/{scene_slug}", get(scenes::get_scene))
|
|
// Spot routes (READ-ONLY)
|
|
.route(
|
|
"/realms/{slug}/scenes/{scene_slug}/spots",
|
|
get(scenes::list_spots),
|
|
)
|
|
.route(
|
|
"/realms/{slug}/scenes/{scene_slug}/spots/{spot_id}",
|
|
get(scenes::get_spot),
|
|
)
|
|
// WebSocket route for channel presence (handles join, leave, position, emotion, members)
|
|
.route(
|
|
"/realms/{slug}/channels/{channel_id}/ws",
|
|
get(websocket::ws_handler::<AppState>),
|
|
)
|
|
// Avatar routes (require authentication)
|
|
.route("/realms/{slug}/avatar", get(avatars::get_avatar))
|
|
.route(
|
|
"/realms/{slug}/avatar/slot",
|
|
axum::routing::put(avatars::assign_slot).delete(avatars::clear_slot),
|
|
)
|
|
// Avatar store routes
|
|
.route("/server/avatars", get(avatars::list_server_avatars))
|
|
.route("/realms/{slug}/avatars", get(avatars::list_realm_avatars))
|
|
.route(
|
|
"/realms/{slug}/avatar/select",
|
|
axum::routing::post(avatars::select_avatar),
|
|
)
|
|
.route(
|
|
"/realms/{slug}/avatar/selection",
|
|
axum::routing::delete(avatars::clear_avatar_selection),
|
|
)
|
|
// User inventory routes
|
|
.route("/user/{uuid}/inventory", get(inventory::get_user_inventory))
|
|
.route(
|
|
"/user/{uuid}/inventory/{item_id}",
|
|
axum::routing::delete(inventory::drop_item),
|
|
)
|
|
// Server prop catalog (enriched if authenticated)
|
|
.route("/server/inventory", get(inventory::get_server_props))
|
|
.route(
|
|
"/server/inventory/request",
|
|
axum::routing::post(inventory::acquire_server_prop),
|
|
)
|
|
// Realm prop catalog (enriched if authenticated)
|
|
.route("/realms/{slug}/inventory", get(inventory::get_realm_props))
|
|
.route(
|
|
"/realms/{slug}/inventory/request",
|
|
axum::routing::post(inventory::acquire_realm_prop),
|
|
)
|
|
}
|