1066 lines
38 KiB
Rust
1066 lines
38 KiB
Rust
//! Realm avatar queries.
|
|
//!
|
|
//! Realm avatars are pre-configured avatar configurations specific to a realm.
|
|
//! They reference realm.props directly (not inventory items).
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use chrono::{Duration, Utc};
|
|
use sqlx::PgExecutor;
|
|
use uuid::Uuid;
|
|
|
|
use crate::models::{AvatarRenderData, EmotionState, RealmAvatar};
|
|
use chattyness_error::AppError;
|
|
|
|
/// Get a realm avatar by slug within a realm.
|
|
pub async fn get_realm_avatar_by_slug<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
slug: &str,
|
|
) -> Result<Option<RealmAvatar>, AppError> {
|
|
let avatar = sqlx::query_as::<_, RealmAvatar>(
|
|
r#"
|
|
SELECT *
|
|
FROM realm.avatars
|
|
WHERE realm_id = $1 AND slug = $2 AND is_active = true
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.bind(slug)
|
|
.fetch_optional(executor)
|
|
.await?;
|
|
|
|
Ok(avatar)
|
|
}
|
|
|
|
/// Get a realm avatar by ID.
|
|
pub async fn get_realm_avatar_by_id<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
avatar_id: Uuid,
|
|
) -> Result<Option<RealmAvatar>, AppError> {
|
|
let avatar = sqlx::query_as::<_, RealmAvatar>(
|
|
r#"
|
|
SELECT *
|
|
FROM realm.avatars
|
|
WHERE id = $1
|
|
"#,
|
|
)
|
|
.bind(avatar_id)
|
|
.fetch_optional(executor)
|
|
.await?;
|
|
|
|
Ok(avatar)
|
|
}
|
|
|
|
/// List all active public realm avatars for a realm.
|
|
pub async fn list_public_realm_avatars<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
) -> Result<Vec<RealmAvatar>, AppError> {
|
|
let avatars = sqlx::query_as::<_, RealmAvatar>(
|
|
r#"
|
|
SELECT *
|
|
FROM realm.avatars
|
|
WHERE realm_id = $1 AND is_active = true AND is_public = true
|
|
ORDER BY name ASC
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.fetch_all(executor)
|
|
.await?;
|
|
|
|
Ok(avatars)
|
|
}
|
|
|
|
use crate::models::RealmAvatarWithPaths;
|
|
|
|
/// Row type for realm avatar with paths query.
|
|
#[derive(Debug, sqlx::FromRow)]
|
|
struct RealmAvatarWithPathsRow {
|
|
id: Uuid,
|
|
name: String,
|
|
description: Option<String>,
|
|
// Skin layer paths
|
|
skin_0: Option<String>,
|
|
skin_1: Option<String>,
|
|
skin_2: Option<String>,
|
|
skin_3: Option<String>,
|
|
skin_4: Option<String>,
|
|
skin_5: Option<String>,
|
|
skin_6: Option<String>,
|
|
skin_7: Option<String>,
|
|
skin_8: Option<String>,
|
|
// Clothes layer paths
|
|
clothes_0: Option<String>,
|
|
clothes_1: Option<String>,
|
|
clothes_2: Option<String>,
|
|
clothes_3: Option<String>,
|
|
clothes_4: Option<String>,
|
|
clothes_5: Option<String>,
|
|
clothes_6: Option<String>,
|
|
clothes_7: Option<String>,
|
|
clothes_8: Option<String>,
|
|
// Accessories layer paths
|
|
accessories_0: Option<String>,
|
|
accessories_1: Option<String>,
|
|
accessories_2: Option<String>,
|
|
accessories_3: Option<String>,
|
|
accessories_4: Option<String>,
|
|
accessories_5: Option<String>,
|
|
accessories_6: Option<String>,
|
|
accessories_7: Option<String>,
|
|
accessories_8: Option<String>,
|
|
// Happy emotion layer paths (e1 - more inviting for store display)
|
|
emotion_0: Option<String>,
|
|
emotion_1: Option<String>,
|
|
emotion_2: Option<String>,
|
|
emotion_3: Option<String>,
|
|
emotion_4: Option<String>,
|
|
emotion_5: Option<String>,
|
|
emotion_6: Option<String>,
|
|
emotion_7: Option<String>,
|
|
emotion_8: Option<String>,
|
|
}
|
|
|
|
impl From<RealmAvatarWithPathsRow> for RealmAvatarWithPaths {
|
|
fn from(row: RealmAvatarWithPathsRow) -> Self {
|
|
Self {
|
|
id: row.id,
|
|
name: row.name,
|
|
description: row.description,
|
|
skin_layer: [
|
|
row.skin_0, row.skin_1, row.skin_2,
|
|
row.skin_3, row.skin_4, row.skin_5,
|
|
row.skin_6, row.skin_7, row.skin_8,
|
|
],
|
|
clothes_layer: [
|
|
row.clothes_0, row.clothes_1, row.clothes_2,
|
|
row.clothes_3, row.clothes_4, row.clothes_5,
|
|
row.clothes_6, row.clothes_7, row.clothes_8,
|
|
],
|
|
accessories_layer: [
|
|
row.accessories_0, row.accessories_1, row.accessories_2,
|
|
row.accessories_3, row.accessories_4, row.accessories_5,
|
|
row.accessories_6, row.accessories_7, row.accessories_8,
|
|
],
|
|
emotion_layer: [
|
|
row.emotion_0, row.emotion_1, row.emotion_2,
|
|
row.emotion_3, row.emotion_4, row.emotion_5,
|
|
row.emotion_6, row.emotion_7, row.emotion_8,
|
|
],
|
|
}
|
|
}
|
|
}
|
|
|
|
/// List all active public realm avatars with resolved asset paths.
|
|
///
|
|
/// Joins with the props table to resolve prop UUIDs to asset paths,
|
|
/// suitable for client-side rendering without additional lookups.
|
|
pub async fn list_public_realm_avatars_with_paths<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
) -> Result<Vec<RealmAvatarWithPaths>, AppError> {
|
|
let rows = sqlx::query_as::<_, RealmAvatarWithPathsRow>(
|
|
r#"
|
|
SELECT
|
|
a.id,
|
|
a.name,
|
|
a.description,
|
|
-- Skin layer
|
|
p_skin_0.asset_path AS skin_0,
|
|
p_skin_1.asset_path AS skin_1,
|
|
p_skin_2.asset_path AS skin_2,
|
|
p_skin_3.asset_path AS skin_3,
|
|
p_skin_4.asset_path AS skin_4,
|
|
p_skin_5.asset_path AS skin_5,
|
|
p_skin_6.asset_path AS skin_6,
|
|
p_skin_7.asset_path AS skin_7,
|
|
p_skin_8.asset_path AS skin_8,
|
|
-- Clothes layer
|
|
p_clothes_0.asset_path AS clothes_0,
|
|
p_clothes_1.asset_path AS clothes_1,
|
|
p_clothes_2.asset_path AS clothes_2,
|
|
p_clothes_3.asset_path AS clothes_3,
|
|
p_clothes_4.asset_path AS clothes_4,
|
|
p_clothes_5.asset_path AS clothes_5,
|
|
p_clothes_6.asset_path AS clothes_6,
|
|
p_clothes_7.asset_path AS clothes_7,
|
|
p_clothes_8.asset_path AS clothes_8,
|
|
-- Accessories layer
|
|
p_acc_0.asset_path AS accessories_0,
|
|
p_acc_1.asset_path AS accessories_1,
|
|
p_acc_2.asset_path AS accessories_2,
|
|
p_acc_3.asset_path AS accessories_3,
|
|
p_acc_4.asset_path AS accessories_4,
|
|
p_acc_5.asset_path AS accessories_5,
|
|
p_acc_6.asset_path AS accessories_6,
|
|
p_acc_7.asset_path AS accessories_7,
|
|
p_acc_8.asset_path AS accessories_8,
|
|
-- Happy emotion layer (e1 - more inviting for store display)
|
|
p_emo_0.asset_path AS emotion_0,
|
|
p_emo_1.asset_path AS emotion_1,
|
|
p_emo_2.asset_path AS emotion_2,
|
|
p_emo_3.asset_path AS emotion_3,
|
|
p_emo_4.asset_path AS emotion_4,
|
|
p_emo_5.asset_path AS emotion_5,
|
|
p_emo_6.asset_path AS emotion_6,
|
|
p_emo_7.asset_path AS emotion_7,
|
|
p_emo_8.asset_path AS emotion_8
|
|
FROM realm.avatars a
|
|
-- Skin layer joins
|
|
LEFT JOIN realm.props p_skin_0 ON a.l_skin_0 = p_skin_0.id
|
|
LEFT JOIN realm.props p_skin_1 ON a.l_skin_1 = p_skin_1.id
|
|
LEFT JOIN realm.props p_skin_2 ON a.l_skin_2 = p_skin_2.id
|
|
LEFT JOIN realm.props p_skin_3 ON a.l_skin_3 = p_skin_3.id
|
|
LEFT JOIN realm.props p_skin_4 ON a.l_skin_4 = p_skin_4.id
|
|
LEFT JOIN realm.props p_skin_5 ON a.l_skin_5 = p_skin_5.id
|
|
LEFT JOIN realm.props p_skin_6 ON a.l_skin_6 = p_skin_6.id
|
|
LEFT JOIN realm.props p_skin_7 ON a.l_skin_7 = p_skin_7.id
|
|
LEFT JOIN realm.props p_skin_8 ON a.l_skin_8 = p_skin_8.id
|
|
-- Clothes layer joins
|
|
LEFT JOIN realm.props p_clothes_0 ON a.l_clothes_0 = p_clothes_0.id
|
|
LEFT JOIN realm.props p_clothes_1 ON a.l_clothes_1 = p_clothes_1.id
|
|
LEFT JOIN realm.props p_clothes_2 ON a.l_clothes_2 = p_clothes_2.id
|
|
LEFT JOIN realm.props p_clothes_3 ON a.l_clothes_3 = p_clothes_3.id
|
|
LEFT JOIN realm.props p_clothes_4 ON a.l_clothes_4 = p_clothes_4.id
|
|
LEFT JOIN realm.props p_clothes_5 ON a.l_clothes_5 = p_clothes_5.id
|
|
LEFT JOIN realm.props p_clothes_6 ON a.l_clothes_6 = p_clothes_6.id
|
|
LEFT JOIN realm.props p_clothes_7 ON a.l_clothes_7 = p_clothes_7.id
|
|
LEFT JOIN realm.props p_clothes_8 ON a.l_clothes_8 = p_clothes_8.id
|
|
-- Accessories layer joins
|
|
LEFT JOIN realm.props p_acc_0 ON a.l_accessories_0 = p_acc_0.id
|
|
LEFT JOIN realm.props p_acc_1 ON a.l_accessories_1 = p_acc_1.id
|
|
LEFT JOIN realm.props p_acc_2 ON a.l_accessories_2 = p_acc_2.id
|
|
LEFT JOIN realm.props p_acc_3 ON a.l_accessories_3 = p_acc_3.id
|
|
LEFT JOIN realm.props p_acc_4 ON a.l_accessories_4 = p_acc_4.id
|
|
LEFT JOIN realm.props p_acc_5 ON a.l_accessories_5 = p_acc_5.id
|
|
LEFT JOIN realm.props p_acc_6 ON a.l_accessories_6 = p_acc_6.id
|
|
LEFT JOIN realm.props p_acc_7 ON a.l_accessories_7 = p_acc_7.id
|
|
LEFT JOIN realm.props p_acc_8 ON a.l_accessories_8 = p_acc_8.id
|
|
-- Happy emotion layer joins (e1 - more inviting for store display)
|
|
LEFT JOIN realm.props p_emo_0 ON a.e_happy_0 = p_emo_0.id
|
|
LEFT JOIN realm.props p_emo_1 ON a.e_happy_1 = p_emo_1.id
|
|
LEFT JOIN realm.props p_emo_2 ON a.e_happy_2 = p_emo_2.id
|
|
LEFT JOIN realm.props p_emo_3 ON a.e_happy_3 = p_emo_3.id
|
|
LEFT JOIN realm.props p_emo_4 ON a.e_happy_4 = p_emo_4.id
|
|
LEFT JOIN realm.props p_emo_5 ON a.e_happy_5 = p_emo_5.id
|
|
LEFT JOIN realm.props p_emo_6 ON a.e_happy_6 = p_emo_6.id
|
|
LEFT JOIN realm.props p_emo_7 ON a.e_happy_7 = p_emo_7.id
|
|
LEFT JOIN realm.props p_emo_8 ON a.e_happy_8 = p_emo_8.id
|
|
WHERE a.realm_id = $1 AND a.is_active = true AND a.is_public = true
|
|
ORDER BY a.name ASC
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.fetch_all(executor)
|
|
.await?;
|
|
|
|
Ok(rows.into_iter().map(RealmAvatarWithPaths::from).collect())
|
|
}
|
|
|
|
/// Row type for prop asset lookup.
|
|
#[derive(Debug, sqlx::FromRow)]
|
|
struct PropAssetRow {
|
|
id: Uuid,
|
|
asset_path: String,
|
|
}
|
|
|
|
/// Resolve a realm avatar to render data.
|
|
/// Joins the avatar's prop UUIDs with realm.props to get asset paths.
|
|
pub async fn resolve_realm_avatar_to_render_data<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
avatar: &RealmAvatar,
|
|
current_emotion: EmotionState,
|
|
) -> Result<AvatarRenderData, AppError> {
|
|
// Collect all non-null prop UUIDs
|
|
let mut prop_ids: Vec<Uuid> = Vec::new();
|
|
|
|
// Content layers
|
|
for id in [
|
|
avatar.l_skin_0, avatar.l_skin_1, avatar.l_skin_2,
|
|
avatar.l_skin_3, avatar.l_skin_4, avatar.l_skin_5,
|
|
avatar.l_skin_6, avatar.l_skin_7, avatar.l_skin_8,
|
|
avatar.l_clothes_0, avatar.l_clothes_1, avatar.l_clothes_2,
|
|
avatar.l_clothes_3, avatar.l_clothes_4, avatar.l_clothes_5,
|
|
avatar.l_clothes_6, avatar.l_clothes_7, avatar.l_clothes_8,
|
|
avatar.l_accessories_0, avatar.l_accessories_1, avatar.l_accessories_2,
|
|
avatar.l_accessories_3, avatar.l_accessories_4, avatar.l_accessories_5,
|
|
avatar.l_accessories_6, avatar.l_accessories_7, avatar.l_accessories_8,
|
|
].iter().flatten() {
|
|
prop_ids.push(*id);
|
|
}
|
|
|
|
// Get emotion layer slots based on current emotion
|
|
let emotion_slots: [Option<Uuid>; 9] = match current_emotion {
|
|
EmotionState::Neutral => [avatar.e_neutral_0, avatar.e_neutral_1, avatar.e_neutral_2,
|
|
avatar.e_neutral_3, avatar.e_neutral_4, avatar.e_neutral_5,
|
|
avatar.e_neutral_6, avatar.e_neutral_7, avatar.e_neutral_8],
|
|
EmotionState::Happy => [avatar.e_happy_0, avatar.e_happy_1, avatar.e_happy_2,
|
|
avatar.e_happy_3, avatar.e_happy_4, avatar.e_happy_5,
|
|
avatar.e_happy_6, avatar.e_happy_7, avatar.e_happy_8],
|
|
EmotionState::Sad => [avatar.e_sad_0, avatar.e_sad_1, avatar.e_sad_2,
|
|
avatar.e_sad_3, avatar.e_sad_4, avatar.e_sad_5,
|
|
avatar.e_sad_6, avatar.e_sad_7, avatar.e_sad_8],
|
|
EmotionState::Angry => [avatar.e_angry_0, avatar.e_angry_1, avatar.e_angry_2,
|
|
avatar.e_angry_3, avatar.e_angry_4, avatar.e_angry_5,
|
|
avatar.e_angry_6, avatar.e_angry_7, avatar.e_angry_8],
|
|
EmotionState::Surprised => [avatar.e_surprised_0, avatar.e_surprised_1, avatar.e_surprised_2,
|
|
avatar.e_surprised_3, avatar.e_surprised_4, avatar.e_surprised_5,
|
|
avatar.e_surprised_6, avatar.e_surprised_7, avatar.e_surprised_8],
|
|
EmotionState::Thinking => [avatar.e_thinking_0, avatar.e_thinking_1, avatar.e_thinking_2,
|
|
avatar.e_thinking_3, avatar.e_thinking_4, avatar.e_thinking_5,
|
|
avatar.e_thinking_6, avatar.e_thinking_7, avatar.e_thinking_8],
|
|
EmotionState::Laughing => [avatar.e_laughing_0, avatar.e_laughing_1, avatar.e_laughing_2,
|
|
avatar.e_laughing_3, avatar.e_laughing_4, avatar.e_laughing_5,
|
|
avatar.e_laughing_6, avatar.e_laughing_7, avatar.e_laughing_8],
|
|
EmotionState::Crying => [avatar.e_crying_0, avatar.e_crying_1, avatar.e_crying_2,
|
|
avatar.e_crying_3, avatar.e_crying_4, avatar.e_crying_5,
|
|
avatar.e_crying_6, avatar.e_crying_7, avatar.e_crying_8],
|
|
EmotionState::Love => [avatar.e_love_0, avatar.e_love_1, avatar.e_love_2,
|
|
avatar.e_love_3, avatar.e_love_4, avatar.e_love_5,
|
|
avatar.e_love_6, avatar.e_love_7, avatar.e_love_8],
|
|
EmotionState::Confused => [avatar.e_confused_0, avatar.e_confused_1, avatar.e_confused_2,
|
|
avatar.e_confused_3, avatar.e_confused_4, avatar.e_confused_5,
|
|
avatar.e_confused_6, avatar.e_confused_7, avatar.e_confused_8],
|
|
EmotionState::Sleeping => [avatar.e_sleeping_0, avatar.e_sleeping_1, avatar.e_sleeping_2,
|
|
avatar.e_sleeping_3, avatar.e_sleeping_4, avatar.e_sleeping_5,
|
|
avatar.e_sleeping_6, avatar.e_sleeping_7, avatar.e_sleeping_8],
|
|
EmotionState::Wink => [avatar.e_wink_0, avatar.e_wink_1, avatar.e_wink_2,
|
|
avatar.e_wink_3, avatar.e_wink_4, avatar.e_wink_5,
|
|
avatar.e_wink_6, avatar.e_wink_7, avatar.e_wink_8],
|
|
};
|
|
|
|
for id in emotion_slots.iter().flatten() {
|
|
prop_ids.push(*id);
|
|
}
|
|
|
|
// Bulk lookup all prop asset paths from realm.props
|
|
let prop_map: HashMap<Uuid, String> = if prop_ids.is_empty() {
|
|
HashMap::new()
|
|
} else {
|
|
let rows = sqlx::query_as::<_, PropAssetRow>(
|
|
r#"
|
|
SELECT id, asset_path
|
|
FROM realm.props
|
|
WHERE id = ANY($1)
|
|
"#,
|
|
)
|
|
.bind(&prop_ids)
|
|
.fetch_all(executor)
|
|
.await?;
|
|
|
|
rows.into_iter().map(|r| (r.id, r.asset_path)).collect()
|
|
};
|
|
|
|
// Helper to look up path
|
|
let get_path = |id: Option<Uuid>| -> Option<String> {
|
|
id.and_then(|id| prop_map.get(&id).cloned())
|
|
};
|
|
|
|
Ok(AvatarRenderData {
|
|
avatar_id: avatar.id,
|
|
current_emotion,
|
|
skin_layer: [
|
|
get_path(avatar.l_skin_0), get_path(avatar.l_skin_1), get_path(avatar.l_skin_2),
|
|
get_path(avatar.l_skin_3), get_path(avatar.l_skin_4), get_path(avatar.l_skin_5),
|
|
get_path(avatar.l_skin_6), get_path(avatar.l_skin_7), get_path(avatar.l_skin_8),
|
|
],
|
|
clothes_layer: [
|
|
get_path(avatar.l_clothes_0), get_path(avatar.l_clothes_1), get_path(avatar.l_clothes_2),
|
|
get_path(avatar.l_clothes_3), get_path(avatar.l_clothes_4), get_path(avatar.l_clothes_5),
|
|
get_path(avatar.l_clothes_6), get_path(avatar.l_clothes_7), get_path(avatar.l_clothes_8),
|
|
],
|
|
accessories_layer: [
|
|
get_path(avatar.l_accessories_0), get_path(avatar.l_accessories_1), get_path(avatar.l_accessories_2),
|
|
get_path(avatar.l_accessories_3), get_path(avatar.l_accessories_4), get_path(avatar.l_accessories_5),
|
|
get_path(avatar.l_accessories_6), get_path(avatar.l_accessories_7), get_path(avatar.l_accessories_8),
|
|
],
|
|
emotion_layer: [
|
|
get_path(emotion_slots[0]), get_path(emotion_slots[1]), get_path(emotion_slots[2]),
|
|
get_path(emotion_slots[3]), get_path(emotion_slots[4]), get_path(emotion_slots[5]),
|
|
get_path(emotion_slots[6]), get_path(emotion_slots[7]), get_path(emotion_slots[8]),
|
|
],
|
|
})
|
|
}
|
|
|
|
/// Apply a forced realm avatar to a user.
|
|
pub async fn apply_forced_realm_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
user_id: Uuid,
|
|
realm_id: Uuid,
|
|
avatar_id: Uuid,
|
|
forced_by: Option<Uuid>,
|
|
duration: Option<Duration>,
|
|
) -> Result<(), AppError> {
|
|
let forced_until = duration.map(|d| Utc::now() + d);
|
|
|
|
sqlx::query(
|
|
r#"
|
|
UPDATE auth.active_avatars
|
|
SET
|
|
forced_avatar_id = $3,
|
|
forced_avatar_source = 'realm',
|
|
forced_by = $4,
|
|
forced_until = $5,
|
|
updated_at = now()
|
|
WHERE user_id = $1 AND realm_id = $2
|
|
"#,
|
|
)
|
|
.bind(user_id)
|
|
.bind(realm_id)
|
|
.bind(avatar_id)
|
|
.bind(forced_by)
|
|
.bind(forced_until)
|
|
.execute(executor)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Get scene forced avatar configuration.
|
|
#[derive(Debug, sqlx::FromRow)]
|
|
pub struct SceneForcedAvatar {
|
|
pub forced_avatar_id: Uuid,
|
|
pub forced_avatar_source: String,
|
|
}
|
|
|
|
pub async fn get_scene_forced_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
scene_id: Uuid,
|
|
) -> Result<Option<SceneForcedAvatar>, AppError> {
|
|
let info = sqlx::query_as::<_, SceneForcedAvatar>(
|
|
r#"
|
|
SELECT forced_avatar_id, forced_avatar_source
|
|
FROM realm.scenes
|
|
WHERE id = $1
|
|
AND forced_avatar_id IS NOT NULL
|
|
"#,
|
|
)
|
|
.bind(scene_id)
|
|
.fetch_optional(executor)
|
|
.await?;
|
|
|
|
Ok(info)
|
|
}
|
|
|
|
/// Apply scene-forced avatar to a user's active avatar.
|
|
pub async fn apply_scene_forced_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
user_id: Uuid,
|
|
realm_id: Uuid,
|
|
avatar_id: Uuid,
|
|
) -> Result<(), AppError> {
|
|
sqlx::query(
|
|
r#"
|
|
UPDATE auth.active_avatars
|
|
SET
|
|
forced_avatar_id = $3,
|
|
forced_avatar_source = 'scene',
|
|
forced_by = NULL,
|
|
forced_until = NULL,
|
|
updated_at = now()
|
|
WHERE user_id = $1 AND realm_id = $2
|
|
"#,
|
|
)
|
|
.bind(user_id)
|
|
.bind(realm_id)
|
|
.bind(avatar_id)
|
|
.execute(executor)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// =============================================================================
|
|
// CRUD Operations for Admin API
|
|
// =============================================================================
|
|
|
|
use crate::models::{CreateRealmAvatarRequest, RealmAvatarSummary, UpdateRealmAvatarRequest};
|
|
|
|
/// List all realm avatars for a realm (for admin).
|
|
pub async fn list_all_realm_avatars<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
) -> Result<Vec<RealmAvatarSummary>, AppError> {
|
|
let avatars = sqlx::query_as::<_, RealmAvatarSummary>(
|
|
r#"
|
|
SELECT id, realm_id, slug, name, description, is_public, is_active, thumbnail_path, created_at
|
|
FROM realm.avatars
|
|
WHERE realm_id = $1
|
|
ORDER BY name ASC
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.fetch_all(executor)
|
|
.await?;
|
|
|
|
Ok(avatars)
|
|
}
|
|
|
|
/// Check if a realm avatar slug is available within a realm.
|
|
pub async fn is_avatar_slug_available<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
slug: &str,
|
|
) -> Result<bool, AppError> {
|
|
let result: (bool,) = sqlx::query_as(
|
|
r#"
|
|
SELECT NOT EXISTS(
|
|
SELECT 1 FROM realm.avatars WHERE realm_id = $1 AND slug = $2
|
|
)
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.bind(slug)
|
|
.fetch_one(executor)
|
|
.await?;
|
|
|
|
Ok(result.0)
|
|
}
|
|
|
|
/// Create a new realm avatar.
|
|
pub async fn create_realm_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
realm_id: Uuid,
|
|
req: &CreateRealmAvatarRequest,
|
|
created_by: Option<Uuid>,
|
|
) -> Result<RealmAvatar, AppError> {
|
|
let slug = req.slug_or_generate();
|
|
|
|
let avatar = sqlx::query_as::<_, RealmAvatar>(
|
|
r#"
|
|
INSERT INTO realm.avatars (
|
|
realm_id, slug, name, description, is_public, is_active, thumbnail_path, created_by,
|
|
l_skin_0, l_skin_1, l_skin_2, l_skin_3, l_skin_4, l_skin_5, l_skin_6, l_skin_7, l_skin_8,
|
|
l_clothes_0, l_clothes_1, l_clothes_2, l_clothes_3, l_clothes_4, l_clothes_5, l_clothes_6, l_clothes_7, l_clothes_8,
|
|
l_accessories_0, l_accessories_1, l_accessories_2, l_accessories_3, l_accessories_4, l_accessories_5, l_accessories_6, l_accessories_7, l_accessories_8,
|
|
e_neutral_0, e_neutral_1, e_neutral_2, e_neutral_3, e_neutral_4, e_neutral_5, e_neutral_6, e_neutral_7, e_neutral_8,
|
|
e_happy_0, e_happy_1, e_happy_2, e_happy_3, e_happy_4, e_happy_5, e_happy_6, e_happy_7, e_happy_8,
|
|
e_sad_0, e_sad_1, e_sad_2, e_sad_3, e_sad_4, e_sad_5, e_sad_6, e_sad_7, e_sad_8,
|
|
e_angry_0, e_angry_1, e_angry_2, e_angry_3, e_angry_4, e_angry_5, e_angry_6, e_angry_7, e_angry_8,
|
|
e_surprised_0, e_surprised_1, e_surprised_2, e_surprised_3, e_surprised_4, e_surprised_5, e_surprised_6, e_surprised_7, e_surprised_8,
|
|
e_thinking_0, e_thinking_1, e_thinking_2, e_thinking_3, e_thinking_4, e_thinking_5, e_thinking_6, e_thinking_7, e_thinking_8,
|
|
e_laughing_0, e_laughing_1, e_laughing_2, e_laughing_3, e_laughing_4, e_laughing_5, e_laughing_6, e_laughing_7, e_laughing_8,
|
|
e_crying_0, e_crying_1, e_crying_2, e_crying_3, e_crying_4, e_crying_5, e_crying_6, e_crying_7, e_crying_8,
|
|
e_love_0, e_love_1, e_love_2, e_love_3, e_love_4, e_love_5, e_love_6, e_love_7, e_love_8,
|
|
e_confused_0, e_confused_1, e_confused_2, e_confused_3, e_confused_4, e_confused_5, e_confused_6, e_confused_7, e_confused_8,
|
|
e_sleeping_0, e_sleeping_1, e_sleeping_2, e_sleeping_3, e_sleeping_4, e_sleeping_5, e_sleeping_6, e_sleeping_7, e_sleeping_8,
|
|
e_wink_0, e_wink_1, e_wink_2, e_wink_3, e_wink_4, e_wink_5, e_wink_6, e_wink_7, e_wink_8
|
|
)
|
|
VALUES (
|
|
$1, $2, $3, $4, $5, true, $6, $7,
|
|
$8, $9, $10, $11, $12, $13, $14, $15, $16,
|
|
$17, $18, $19, $20, $21, $22, $23, $24, $25,
|
|
$26, $27, $28, $29, $30, $31, $32, $33, $34,
|
|
$35, $36, $37, $38, $39, $40, $41, $42, $43,
|
|
$44, $45, $46, $47, $48, $49, $50, $51, $52,
|
|
$53, $54, $55, $56, $57, $58, $59, $60, $61,
|
|
$62, $63, $64, $65, $66, $67, $68, $69, $70,
|
|
$71, $72, $73, $74, $75, $76, $77, $78, $79,
|
|
$80, $81, $82, $83, $84, $85, $86, $87, $88,
|
|
$89, $90, $91, $92, $93, $94, $95, $96, $97,
|
|
$98, $99, $100, $101, $102, $103, $104, $105, $106,
|
|
$107, $108, $109, $110, $111, $112, $113, $114, $115,
|
|
$116, $117, $118, $119, $120, $121, $122, $123, $124,
|
|
$125, $126, $127, $128, $129, $130, $131, $132, $133,
|
|
$134, $135, $136, $137, $138, $139, $140, $141, $142
|
|
)
|
|
RETURNING *
|
|
"#,
|
|
)
|
|
.bind(realm_id)
|
|
.bind(&slug)
|
|
.bind(&req.name)
|
|
.bind(&req.description)
|
|
.bind(req.is_public)
|
|
.bind(&req.thumbnail_path)
|
|
.bind(created_by)
|
|
// Skin layer
|
|
.bind(req.l_skin_0)
|
|
.bind(req.l_skin_1)
|
|
.bind(req.l_skin_2)
|
|
.bind(req.l_skin_3)
|
|
.bind(req.l_skin_4)
|
|
.bind(req.l_skin_5)
|
|
.bind(req.l_skin_6)
|
|
.bind(req.l_skin_7)
|
|
.bind(req.l_skin_8)
|
|
// Clothes layer
|
|
.bind(req.l_clothes_0)
|
|
.bind(req.l_clothes_1)
|
|
.bind(req.l_clothes_2)
|
|
.bind(req.l_clothes_3)
|
|
.bind(req.l_clothes_4)
|
|
.bind(req.l_clothes_5)
|
|
.bind(req.l_clothes_6)
|
|
.bind(req.l_clothes_7)
|
|
.bind(req.l_clothes_8)
|
|
// Accessories layer
|
|
.bind(req.l_accessories_0)
|
|
.bind(req.l_accessories_1)
|
|
.bind(req.l_accessories_2)
|
|
.bind(req.l_accessories_3)
|
|
.bind(req.l_accessories_4)
|
|
.bind(req.l_accessories_5)
|
|
.bind(req.l_accessories_6)
|
|
.bind(req.l_accessories_7)
|
|
.bind(req.l_accessories_8)
|
|
// Neutral emotion
|
|
.bind(req.e_neutral_0)
|
|
.bind(req.e_neutral_1)
|
|
.bind(req.e_neutral_2)
|
|
.bind(req.e_neutral_3)
|
|
.bind(req.e_neutral_4)
|
|
.bind(req.e_neutral_5)
|
|
.bind(req.e_neutral_6)
|
|
.bind(req.e_neutral_7)
|
|
.bind(req.e_neutral_8)
|
|
// Happy emotion
|
|
.bind(req.e_happy_0)
|
|
.bind(req.e_happy_1)
|
|
.bind(req.e_happy_2)
|
|
.bind(req.e_happy_3)
|
|
.bind(req.e_happy_4)
|
|
.bind(req.e_happy_5)
|
|
.bind(req.e_happy_6)
|
|
.bind(req.e_happy_7)
|
|
.bind(req.e_happy_8)
|
|
// Sad emotion
|
|
.bind(req.e_sad_0)
|
|
.bind(req.e_sad_1)
|
|
.bind(req.e_sad_2)
|
|
.bind(req.e_sad_3)
|
|
.bind(req.e_sad_4)
|
|
.bind(req.e_sad_5)
|
|
.bind(req.e_sad_6)
|
|
.bind(req.e_sad_7)
|
|
.bind(req.e_sad_8)
|
|
// Angry emotion
|
|
.bind(req.e_angry_0)
|
|
.bind(req.e_angry_1)
|
|
.bind(req.e_angry_2)
|
|
.bind(req.e_angry_3)
|
|
.bind(req.e_angry_4)
|
|
.bind(req.e_angry_5)
|
|
.bind(req.e_angry_6)
|
|
.bind(req.e_angry_7)
|
|
.bind(req.e_angry_8)
|
|
// Surprised emotion
|
|
.bind(req.e_surprised_0)
|
|
.bind(req.e_surprised_1)
|
|
.bind(req.e_surprised_2)
|
|
.bind(req.e_surprised_3)
|
|
.bind(req.e_surprised_4)
|
|
.bind(req.e_surprised_5)
|
|
.bind(req.e_surprised_6)
|
|
.bind(req.e_surprised_7)
|
|
.bind(req.e_surprised_8)
|
|
// Thinking emotion
|
|
.bind(req.e_thinking_0)
|
|
.bind(req.e_thinking_1)
|
|
.bind(req.e_thinking_2)
|
|
.bind(req.e_thinking_3)
|
|
.bind(req.e_thinking_4)
|
|
.bind(req.e_thinking_5)
|
|
.bind(req.e_thinking_6)
|
|
.bind(req.e_thinking_7)
|
|
.bind(req.e_thinking_8)
|
|
// Laughing emotion
|
|
.bind(req.e_laughing_0)
|
|
.bind(req.e_laughing_1)
|
|
.bind(req.e_laughing_2)
|
|
.bind(req.e_laughing_3)
|
|
.bind(req.e_laughing_4)
|
|
.bind(req.e_laughing_5)
|
|
.bind(req.e_laughing_6)
|
|
.bind(req.e_laughing_7)
|
|
.bind(req.e_laughing_8)
|
|
// Crying emotion
|
|
.bind(req.e_crying_0)
|
|
.bind(req.e_crying_1)
|
|
.bind(req.e_crying_2)
|
|
.bind(req.e_crying_3)
|
|
.bind(req.e_crying_4)
|
|
.bind(req.e_crying_5)
|
|
.bind(req.e_crying_6)
|
|
.bind(req.e_crying_7)
|
|
.bind(req.e_crying_8)
|
|
// Love emotion
|
|
.bind(req.e_love_0)
|
|
.bind(req.e_love_1)
|
|
.bind(req.e_love_2)
|
|
.bind(req.e_love_3)
|
|
.bind(req.e_love_4)
|
|
.bind(req.e_love_5)
|
|
.bind(req.e_love_6)
|
|
.bind(req.e_love_7)
|
|
.bind(req.e_love_8)
|
|
// Confused emotion
|
|
.bind(req.e_confused_0)
|
|
.bind(req.e_confused_1)
|
|
.bind(req.e_confused_2)
|
|
.bind(req.e_confused_3)
|
|
.bind(req.e_confused_4)
|
|
.bind(req.e_confused_5)
|
|
.bind(req.e_confused_6)
|
|
.bind(req.e_confused_7)
|
|
.bind(req.e_confused_8)
|
|
// Sleeping emotion
|
|
.bind(req.e_sleeping_0)
|
|
.bind(req.e_sleeping_1)
|
|
.bind(req.e_sleeping_2)
|
|
.bind(req.e_sleeping_3)
|
|
.bind(req.e_sleeping_4)
|
|
.bind(req.e_sleeping_5)
|
|
.bind(req.e_sleeping_6)
|
|
.bind(req.e_sleeping_7)
|
|
.bind(req.e_sleeping_8)
|
|
// Wink emotion
|
|
.bind(req.e_wink_0)
|
|
.bind(req.e_wink_1)
|
|
.bind(req.e_wink_2)
|
|
.bind(req.e_wink_3)
|
|
.bind(req.e_wink_4)
|
|
.bind(req.e_wink_5)
|
|
.bind(req.e_wink_6)
|
|
.bind(req.e_wink_7)
|
|
.bind(req.e_wink_8)
|
|
.fetch_one(executor)
|
|
.await?;
|
|
|
|
Ok(avatar)
|
|
}
|
|
|
|
/// Update a realm avatar.
|
|
pub async fn update_realm_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
avatar_id: Uuid,
|
|
req: &UpdateRealmAvatarRequest,
|
|
) -> Result<RealmAvatar, AppError> {
|
|
let avatar = sqlx::query_as::<_, RealmAvatar>(
|
|
r#"
|
|
UPDATE realm.avatars SET
|
|
name = COALESCE($2, name),
|
|
description = COALESCE($3, description),
|
|
is_public = COALESCE($4, is_public),
|
|
is_active = COALESCE($5, is_active),
|
|
thumbnail_path = COALESCE($6, thumbnail_path),
|
|
l_skin_0 = COALESCE($7, l_skin_0),
|
|
l_skin_1 = COALESCE($8, l_skin_1),
|
|
l_skin_2 = COALESCE($9, l_skin_2),
|
|
l_skin_3 = COALESCE($10, l_skin_3),
|
|
l_skin_4 = COALESCE($11, l_skin_4),
|
|
l_skin_5 = COALESCE($12, l_skin_5),
|
|
l_skin_6 = COALESCE($13, l_skin_6),
|
|
l_skin_7 = COALESCE($14, l_skin_7),
|
|
l_skin_8 = COALESCE($15, l_skin_8),
|
|
l_clothes_0 = COALESCE($16, l_clothes_0),
|
|
l_clothes_1 = COALESCE($17, l_clothes_1),
|
|
l_clothes_2 = COALESCE($18, l_clothes_2),
|
|
l_clothes_3 = COALESCE($19, l_clothes_3),
|
|
l_clothes_4 = COALESCE($20, l_clothes_4),
|
|
l_clothes_5 = COALESCE($21, l_clothes_5),
|
|
l_clothes_6 = COALESCE($22, l_clothes_6),
|
|
l_clothes_7 = COALESCE($23, l_clothes_7),
|
|
l_clothes_8 = COALESCE($24, l_clothes_8),
|
|
l_accessories_0 = COALESCE($25, l_accessories_0),
|
|
l_accessories_1 = COALESCE($26, l_accessories_1),
|
|
l_accessories_2 = COALESCE($27, l_accessories_2),
|
|
l_accessories_3 = COALESCE($28, l_accessories_3),
|
|
l_accessories_4 = COALESCE($29, l_accessories_4),
|
|
l_accessories_5 = COALESCE($30, l_accessories_5),
|
|
l_accessories_6 = COALESCE($31, l_accessories_6),
|
|
l_accessories_7 = COALESCE($32, l_accessories_7),
|
|
l_accessories_8 = COALESCE($33, l_accessories_8),
|
|
e_neutral_0 = COALESCE($34, e_neutral_0),
|
|
e_neutral_1 = COALESCE($35, e_neutral_1),
|
|
e_neutral_2 = COALESCE($36, e_neutral_2),
|
|
e_neutral_3 = COALESCE($37, e_neutral_3),
|
|
e_neutral_4 = COALESCE($38, e_neutral_4),
|
|
e_neutral_5 = COALESCE($39, e_neutral_5),
|
|
e_neutral_6 = COALESCE($40, e_neutral_6),
|
|
e_neutral_7 = COALESCE($41, e_neutral_7),
|
|
e_neutral_8 = COALESCE($42, e_neutral_8),
|
|
e_happy_0 = COALESCE($43, e_happy_0),
|
|
e_happy_1 = COALESCE($44, e_happy_1),
|
|
e_happy_2 = COALESCE($45, e_happy_2),
|
|
e_happy_3 = COALESCE($46, e_happy_3),
|
|
e_happy_4 = COALESCE($47, e_happy_4),
|
|
e_happy_5 = COALESCE($48, e_happy_5),
|
|
e_happy_6 = COALESCE($49, e_happy_6),
|
|
e_happy_7 = COALESCE($50, e_happy_7),
|
|
e_happy_8 = COALESCE($51, e_happy_8),
|
|
e_sad_0 = COALESCE($52, e_sad_0),
|
|
e_sad_1 = COALESCE($53, e_sad_1),
|
|
e_sad_2 = COALESCE($54, e_sad_2),
|
|
e_sad_3 = COALESCE($55, e_sad_3),
|
|
e_sad_4 = COALESCE($56, e_sad_4),
|
|
e_sad_5 = COALESCE($57, e_sad_5),
|
|
e_sad_6 = COALESCE($58, e_sad_6),
|
|
e_sad_7 = COALESCE($59, e_sad_7),
|
|
e_sad_8 = COALESCE($60, e_sad_8),
|
|
e_angry_0 = COALESCE($61, e_angry_0),
|
|
e_angry_1 = COALESCE($62, e_angry_1),
|
|
e_angry_2 = COALESCE($63, e_angry_2),
|
|
e_angry_3 = COALESCE($64, e_angry_3),
|
|
e_angry_4 = COALESCE($65, e_angry_4),
|
|
e_angry_5 = COALESCE($66, e_angry_5),
|
|
e_angry_6 = COALESCE($67, e_angry_6),
|
|
e_angry_7 = COALESCE($68, e_angry_7),
|
|
e_angry_8 = COALESCE($69, e_angry_8),
|
|
e_surprised_0 = COALESCE($70, e_surprised_0),
|
|
e_surprised_1 = COALESCE($71, e_surprised_1),
|
|
e_surprised_2 = COALESCE($72, e_surprised_2),
|
|
e_surprised_3 = COALESCE($73, e_surprised_3),
|
|
e_surprised_4 = COALESCE($74, e_surprised_4),
|
|
e_surprised_5 = COALESCE($75, e_surprised_5),
|
|
e_surprised_6 = COALESCE($76, e_surprised_6),
|
|
e_surprised_7 = COALESCE($77, e_surprised_7),
|
|
e_surprised_8 = COALESCE($78, e_surprised_8),
|
|
e_thinking_0 = COALESCE($79, e_thinking_0),
|
|
e_thinking_1 = COALESCE($80, e_thinking_1),
|
|
e_thinking_2 = COALESCE($81, e_thinking_2),
|
|
e_thinking_3 = COALESCE($82, e_thinking_3),
|
|
e_thinking_4 = COALESCE($83, e_thinking_4),
|
|
e_thinking_5 = COALESCE($84, e_thinking_5),
|
|
e_thinking_6 = COALESCE($85, e_thinking_6),
|
|
e_thinking_7 = COALESCE($86, e_thinking_7),
|
|
e_thinking_8 = COALESCE($87, e_thinking_8),
|
|
e_laughing_0 = COALESCE($88, e_laughing_0),
|
|
e_laughing_1 = COALESCE($89, e_laughing_1),
|
|
e_laughing_2 = COALESCE($90, e_laughing_2),
|
|
e_laughing_3 = COALESCE($91, e_laughing_3),
|
|
e_laughing_4 = COALESCE($92, e_laughing_4),
|
|
e_laughing_5 = COALESCE($93, e_laughing_5),
|
|
e_laughing_6 = COALESCE($94, e_laughing_6),
|
|
e_laughing_7 = COALESCE($95, e_laughing_7),
|
|
e_laughing_8 = COALESCE($96, e_laughing_8),
|
|
e_crying_0 = COALESCE($97, e_crying_0),
|
|
e_crying_1 = COALESCE($98, e_crying_1),
|
|
e_crying_2 = COALESCE($99, e_crying_2),
|
|
e_crying_3 = COALESCE($100, e_crying_3),
|
|
e_crying_4 = COALESCE($101, e_crying_4),
|
|
e_crying_5 = COALESCE($102, e_crying_5),
|
|
e_crying_6 = COALESCE($103, e_crying_6),
|
|
e_crying_7 = COALESCE($104, e_crying_7),
|
|
e_crying_8 = COALESCE($105, e_crying_8),
|
|
e_love_0 = COALESCE($106, e_love_0),
|
|
e_love_1 = COALESCE($107, e_love_1),
|
|
e_love_2 = COALESCE($108, e_love_2),
|
|
e_love_3 = COALESCE($109, e_love_3),
|
|
e_love_4 = COALESCE($110, e_love_4),
|
|
e_love_5 = COALESCE($111, e_love_5),
|
|
e_love_6 = COALESCE($112, e_love_6),
|
|
e_love_7 = COALESCE($113, e_love_7),
|
|
e_love_8 = COALESCE($114, e_love_8),
|
|
e_confused_0 = COALESCE($115, e_confused_0),
|
|
e_confused_1 = COALESCE($116, e_confused_1),
|
|
e_confused_2 = COALESCE($117, e_confused_2),
|
|
e_confused_3 = COALESCE($118, e_confused_3),
|
|
e_confused_4 = COALESCE($119, e_confused_4),
|
|
e_confused_5 = COALESCE($120, e_confused_5),
|
|
e_confused_6 = COALESCE($121, e_confused_6),
|
|
e_confused_7 = COALESCE($122, e_confused_7),
|
|
e_confused_8 = COALESCE($123, e_confused_8),
|
|
e_sleeping_0 = COALESCE($124, e_sleeping_0),
|
|
e_sleeping_1 = COALESCE($125, e_sleeping_1),
|
|
e_sleeping_2 = COALESCE($126, e_sleeping_2),
|
|
e_sleeping_3 = COALESCE($127, e_sleeping_3),
|
|
e_sleeping_4 = COALESCE($128, e_sleeping_4),
|
|
e_sleeping_5 = COALESCE($129, e_sleeping_5),
|
|
e_sleeping_6 = COALESCE($130, e_sleeping_6),
|
|
e_sleeping_7 = COALESCE($131, e_sleeping_7),
|
|
e_sleeping_8 = COALESCE($132, e_sleeping_8),
|
|
e_wink_0 = COALESCE($133, e_wink_0),
|
|
e_wink_1 = COALESCE($134, e_wink_1),
|
|
e_wink_2 = COALESCE($135, e_wink_2),
|
|
e_wink_3 = COALESCE($136, e_wink_3),
|
|
e_wink_4 = COALESCE($137, e_wink_4),
|
|
e_wink_5 = COALESCE($138, e_wink_5),
|
|
e_wink_6 = COALESCE($139, e_wink_6),
|
|
e_wink_7 = COALESCE($140, e_wink_7),
|
|
e_wink_8 = COALESCE($141, e_wink_8),
|
|
updated_at = now()
|
|
WHERE id = $1
|
|
RETURNING *
|
|
"#,
|
|
)
|
|
.bind(avatar_id)
|
|
.bind(&req.name)
|
|
.bind(&req.description)
|
|
.bind(req.is_public)
|
|
.bind(req.is_active)
|
|
.bind(&req.thumbnail_path)
|
|
// Skin layer
|
|
.bind(req.l_skin_0)
|
|
.bind(req.l_skin_1)
|
|
.bind(req.l_skin_2)
|
|
.bind(req.l_skin_3)
|
|
.bind(req.l_skin_4)
|
|
.bind(req.l_skin_5)
|
|
.bind(req.l_skin_6)
|
|
.bind(req.l_skin_7)
|
|
.bind(req.l_skin_8)
|
|
// Clothes layer
|
|
.bind(req.l_clothes_0)
|
|
.bind(req.l_clothes_1)
|
|
.bind(req.l_clothes_2)
|
|
.bind(req.l_clothes_3)
|
|
.bind(req.l_clothes_4)
|
|
.bind(req.l_clothes_5)
|
|
.bind(req.l_clothes_6)
|
|
.bind(req.l_clothes_7)
|
|
.bind(req.l_clothes_8)
|
|
// Accessories layer
|
|
.bind(req.l_accessories_0)
|
|
.bind(req.l_accessories_1)
|
|
.bind(req.l_accessories_2)
|
|
.bind(req.l_accessories_3)
|
|
.bind(req.l_accessories_4)
|
|
.bind(req.l_accessories_5)
|
|
.bind(req.l_accessories_6)
|
|
.bind(req.l_accessories_7)
|
|
.bind(req.l_accessories_8)
|
|
// Neutral emotion
|
|
.bind(req.e_neutral_0)
|
|
.bind(req.e_neutral_1)
|
|
.bind(req.e_neutral_2)
|
|
.bind(req.e_neutral_3)
|
|
.bind(req.e_neutral_4)
|
|
.bind(req.e_neutral_5)
|
|
.bind(req.e_neutral_6)
|
|
.bind(req.e_neutral_7)
|
|
.bind(req.e_neutral_8)
|
|
// Happy emotion
|
|
.bind(req.e_happy_0)
|
|
.bind(req.e_happy_1)
|
|
.bind(req.e_happy_2)
|
|
.bind(req.e_happy_3)
|
|
.bind(req.e_happy_4)
|
|
.bind(req.e_happy_5)
|
|
.bind(req.e_happy_6)
|
|
.bind(req.e_happy_7)
|
|
.bind(req.e_happy_8)
|
|
// Sad emotion
|
|
.bind(req.e_sad_0)
|
|
.bind(req.e_sad_1)
|
|
.bind(req.e_sad_2)
|
|
.bind(req.e_sad_3)
|
|
.bind(req.e_sad_4)
|
|
.bind(req.e_sad_5)
|
|
.bind(req.e_sad_6)
|
|
.bind(req.e_sad_7)
|
|
.bind(req.e_sad_8)
|
|
// Angry emotion
|
|
.bind(req.e_angry_0)
|
|
.bind(req.e_angry_1)
|
|
.bind(req.e_angry_2)
|
|
.bind(req.e_angry_3)
|
|
.bind(req.e_angry_4)
|
|
.bind(req.e_angry_5)
|
|
.bind(req.e_angry_6)
|
|
.bind(req.e_angry_7)
|
|
.bind(req.e_angry_8)
|
|
// Surprised emotion
|
|
.bind(req.e_surprised_0)
|
|
.bind(req.e_surprised_1)
|
|
.bind(req.e_surprised_2)
|
|
.bind(req.e_surprised_3)
|
|
.bind(req.e_surprised_4)
|
|
.bind(req.e_surprised_5)
|
|
.bind(req.e_surprised_6)
|
|
.bind(req.e_surprised_7)
|
|
.bind(req.e_surprised_8)
|
|
// Thinking emotion
|
|
.bind(req.e_thinking_0)
|
|
.bind(req.e_thinking_1)
|
|
.bind(req.e_thinking_2)
|
|
.bind(req.e_thinking_3)
|
|
.bind(req.e_thinking_4)
|
|
.bind(req.e_thinking_5)
|
|
.bind(req.e_thinking_6)
|
|
.bind(req.e_thinking_7)
|
|
.bind(req.e_thinking_8)
|
|
// Laughing emotion
|
|
.bind(req.e_laughing_0)
|
|
.bind(req.e_laughing_1)
|
|
.bind(req.e_laughing_2)
|
|
.bind(req.e_laughing_3)
|
|
.bind(req.e_laughing_4)
|
|
.bind(req.e_laughing_5)
|
|
.bind(req.e_laughing_6)
|
|
.bind(req.e_laughing_7)
|
|
.bind(req.e_laughing_8)
|
|
// Crying emotion
|
|
.bind(req.e_crying_0)
|
|
.bind(req.e_crying_1)
|
|
.bind(req.e_crying_2)
|
|
.bind(req.e_crying_3)
|
|
.bind(req.e_crying_4)
|
|
.bind(req.e_crying_5)
|
|
.bind(req.e_crying_6)
|
|
.bind(req.e_crying_7)
|
|
.bind(req.e_crying_8)
|
|
// Love emotion
|
|
.bind(req.e_love_0)
|
|
.bind(req.e_love_1)
|
|
.bind(req.e_love_2)
|
|
.bind(req.e_love_3)
|
|
.bind(req.e_love_4)
|
|
.bind(req.e_love_5)
|
|
.bind(req.e_love_6)
|
|
.bind(req.e_love_7)
|
|
.bind(req.e_love_8)
|
|
// Confused emotion
|
|
.bind(req.e_confused_0)
|
|
.bind(req.e_confused_1)
|
|
.bind(req.e_confused_2)
|
|
.bind(req.e_confused_3)
|
|
.bind(req.e_confused_4)
|
|
.bind(req.e_confused_5)
|
|
.bind(req.e_confused_6)
|
|
.bind(req.e_confused_7)
|
|
.bind(req.e_confused_8)
|
|
// Sleeping emotion
|
|
.bind(req.e_sleeping_0)
|
|
.bind(req.e_sleeping_1)
|
|
.bind(req.e_sleeping_2)
|
|
.bind(req.e_sleeping_3)
|
|
.bind(req.e_sleeping_4)
|
|
.bind(req.e_sleeping_5)
|
|
.bind(req.e_sleeping_6)
|
|
.bind(req.e_sleeping_7)
|
|
.bind(req.e_sleeping_8)
|
|
// Wink emotion
|
|
.bind(req.e_wink_0)
|
|
.bind(req.e_wink_1)
|
|
.bind(req.e_wink_2)
|
|
.bind(req.e_wink_3)
|
|
.bind(req.e_wink_4)
|
|
.bind(req.e_wink_5)
|
|
.bind(req.e_wink_6)
|
|
.bind(req.e_wink_7)
|
|
.bind(req.e_wink_8)
|
|
.fetch_one(executor)
|
|
.await?;
|
|
|
|
Ok(avatar)
|
|
}
|
|
|
|
/// Delete a realm avatar.
|
|
pub async fn delete_realm_avatar<'e>(
|
|
executor: impl PgExecutor<'e>,
|
|
avatar_id: Uuid,
|
|
) -> Result<(), AppError> {
|
|
sqlx::query(
|
|
r#"
|
|
DELETE FROM realm.avatars
|
|
WHERE id = $1
|
|
"#,
|
|
)
|
|
.bind(avatar_id)
|
|
.execute(executor)
|
|
.await?;
|
|
|
|
Ok(())
|
|
}
|