Silence warnings, run cargo fmt
This commit is contained in:
parent
fe1c1d3655
commit
af1c767f5f
77 changed files with 1904 additions and 903 deletions
|
|
@ -11,6 +11,6 @@ pub mod pool;
|
|||
pub mod queries;
|
||||
|
||||
pub use models::*;
|
||||
pub use ws_messages::*;
|
||||
#[cfg(feature = "ssr")]
|
||||
pub use pool::*;
|
||||
pub use ws_messages::*;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,10 @@ use chattyness_shared::validation;
|
|||
/// Realm privacy setting.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "realm_privacy", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "realm_privacy", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RealmPrivacy {
|
||||
#[default]
|
||||
|
|
@ -64,7 +67,10 @@ impl RealmPrivacy {
|
|||
/// Server-wide reputation tier.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "reputation_tier", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "reputation_tier", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ReputationTier {
|
||||
Guest,
|
||||
|
|
@ -78,7 +84,10 @@ pub enum ReputationTier {
|
|||
/// User account status.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "account_status", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "account_status", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AccountStatus {
|
||||
#[default]
|
||||
|
|
@ -91,7 +100,10 @@ pub enum AccountStatus {
|
|||
/// User account tag for feature gating and access control.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "user_tag", rename_all = "snake_case"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "user_tag", rename_all = "snake_case")
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum UserTag {
|
||||
Guest,
|
||||
|
|
@ -105,7 +117,10 @@ pub enum UserTag {
|
|||
/// Authentication provider.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "auth_provider", rename_all = "snake_case"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "auth_provider", rename_all = "snake_case")
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AuthProvider {
|
||||
#[default]
|
||||
|
|
@ -118,7 +133,10 @@ pub enum AuthProvider {
|
|||
/// Server-level staff role.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "server_role", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "server_role", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ServerRole {
|
||||
#[default]
|
||||
|
|
@ -153,7 +171,10 @@ impl std::str::FromStr for ServerRole {
|
|||
/// Realm membership role.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "realm_role", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "realm_role", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum RealmRole {
|
||||
#[default]
|
||||
|
|
@ -191,7 +212,10 @@ impl std::str::FromStr for RealmRole {
|
|||
/// Scene dimension mode.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "dimension_mode", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "dimension_mode", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum DimensionMode {
|
||||
#[default]
|
||||
|
|
@ -223,7 +247,10 @@ impl std::str::FromStr for DimensionMode {
|
|||
/// Interactive spot type.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "spot_type", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "spot_type", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SpotType {
|
||||
#[default]
|
||||
|
|
@ -258,7 +285,10 @@ impl std::str::FromStr for SpotType {
|
|||
/// Avatar layer for prop positioning (z-depth).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "avatar_layer", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "avatar_layer", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AvatarLayer {
|
||||
Skin,
|
||||
|
|
@ -298,7 +328,10 @@ impl std::str::FromStr for AvatarLayer {
|
|||
/// - e10: sleeping, e11: wink
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "emotion_state", rename_all = "lowercase"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "emotion_state", rename_all = "lowercase")
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum EmotionState {
|
||||
#[default]
|
||||
|
|
@ -600,7 +633,10 @@ pub struct SpotSummary {
|
|||
/// Origin source for a prop in inventory.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::Type))]
|
||||
#[cfg_attr(feature = "ssr", sqlx(type_name = "prop_origin", rename_all = "snake_case"))]
|
||||
#[cfg_attr(
|
||||
feature = "ssr",
|
||||
sqlx(type_name = "prop_origin", rename_all = "snake_case")
|
||||
)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PropOrigin {
|
||||
#[default]
|
||||
|
|
@ -773,7 +809,8 @@ impl CreateServerPropRequest {
|
|||
&& self.default_position.is_none()
|
||||
{
|
||||
return Err(AppError::Validation(
|
||||
"default_position is required when default_layer or default_emotion is set".to_string(),
|
||||
"default_position is required when default_layer or default_emotion is set"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::time::Duration;
|
||||
|
||||
use sqlx::{postgres::PgPoolOptions, PgPool};
|
||||
use sqlx::{PgPool, postgres::PgPoolOptions};
|
||||
use uuid::Uuid;
|
||||
|
||||
use chattyness_error::AppError;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,10 @@ pub async fn create_guest_session(
|
|||
}
|
||||
|
||||
/// Get a guest session by ID.
|
||||
pub async fn get_guest_session(pool: &PgPool, session_id: Uuid) -> Result<Option<GuestSession>, AppError> {
|
||||
pub async fn get_guest_session(
|
||||
pool: &PgPool,
|
||||
session_id: Uuid,
|
||||
) -> Result<Option<GuestSession>, AppError> {
|
||||
let session = sqlx::query_as::<_, GuestSession>(
|
||||
r#"
|
||||
SELECT id, guest_name, current_realm_id, expires_at, created_at
|
||||
|
|
|
|||
|
|
@ -57,7 +57,22 @@ pub async fn drop_prop_to_canvas<'e>(
|
|||
) -> Result<LooseProp, AppError> {
|
||||
// Single CTE that checks existence/droppability and performs the operation atomically.
|
||||
// Returns status flags plus the LooseProp data (if successful).
|
||||
let result: Option<(bool, bool, bool, Option<Uuid>, Option<Uuid>, Option<Uuid>, Option<Uuid>, Option<f32>, Option<f32>, Option<Uuid>, Option<chrono::DateTime<chrono::Utc>>, Option<chrono::DateTime<chrono::Utc>>, Option<String>, Option<String>)> = sqlx::query_as(
|
||||
let result: Option<(
|
||||
bool,
|
||||
bool,
|
||||
bool,
|
||||
Option<Uuid>,
|
||||
Option<Uuid>,
|
||||
Option<Uuid>,
|
||||
Option<Uuid>,
|
||||
Option<f32>,
|
||||
Option<f32>,
|
||||
Option<Uuid>,
|
||||
Option<chrono::DateTime<chrono::Utc>>,
|
||||
Option<chrono::DateTime<chrono::Utc>>,
|
||||
Option<String>,
|
||||
Option<String>,
|
||||
)> = sqlx::query_as(
|
||||
r#"
|
||||
WITH item_info AS (
|
||||
SELECT id, is_droppable, server_prop_id, realm_prop_id, prop_name, prop_asset_path
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ use chattyness_error::AppError;
|
|||
/// Hash a password using argon2.
|
||||
pub fn hash_password(password: &str) -> Result<String, AppError> {
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, PasswordHasher, SaltString},
|
||||
Argon2,
|
||||
password_hash::{PasswordHasher, SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
|
|
|||
|
|
@ -95,25 +95,24 @@ pub async fn create_server_prop<'e>(
|
|||
|
||||
// Positioning: either content layer OR emotion layer OR neither (all NULL)
|
||||
// Database constraint enforces mutual exclusivity
|
||||
let (default_layer, default_emotion, default_position) =
|
||||
if req.default_layer.is_some() {
|
||||
// Content layer prop
|
||||
(
|
||||
req.default_layer.map(|l| l.to_string()),
|
||||
None,
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else if req.default_emotion.is_some() {
|
||||
// Emotion layer prop
|
||||
(
|
||||
None,
|
||||
req.default_emotion.map(|e| e.to_string()),
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else {
|
||||
// Non-avatar prop
|
||||
(None, None, None)
|
||||
};
|
||||
let (default_layer, default_emotion, default_position) = if req.default_layer.is_some() {
|
||||
// Content layer prop
|
||||
(
|
||||
req.default_layer.map(|l| l.to_string()),
|
||||
None,
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else if req.default_emotion.is_some() {
|
||||
// Emotion layer prop
|
||||
(
|
||||
None,
|
||||
req.default_emotion.map(|e| e.to_string()),
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else {
|
||||
// Non-avatar prop
|
||||
(None, None, None)
|
||||
};
|
||||
|
||||
let is_droppable = req.droppable.unwrap_or(true);
|
||||
let is_public = req.public.unwrap_or(false);
|
||||
|
|
@ -187,25 +186,24 @@ pub async fn upsert_server_prop<'e>(
|
|||
|
||||
// Positioning: either content layer OR emotion layer OR neither (all NULL)
|
||||
// Database constraint enforces mutual exclusivity
|
||||
let (default_layer, default_emotion, default_position) =
|
||||
if req.default_layer.is_some() {
|
||||
// Content layer prop
|
||||
(
|
||||
req.default_layer.map(|l| l.to_string()),
|
||||
None,
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else if req.default_emotion.is_some() {
|
||||
// Emotion layer prop
|
||||
(
|
||||
None,
|
||||
req.default_emotion.map(|e| e.to_string()),
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else {
|
||||
// Non-avatar prop
|
||||
(None, None, None)
|
||||
};
|
||||
let (default_layer, default_emotion, default_position) = if req.default_layer.is_some() {
|
||||
// Content layer prop
|
||||
(
|
||||
req.default_layer.map(|l| l.to_string()),
|
||||
None,
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else if req.default_emotion.is_some() {
|
||||
// Emotion layer prop
|
||||
(
|
||||
None,
|
||||
req.default_emotion.map(|e| e.to_string()),
|
||||
Some(req.default_position.unwrap_or(4)), // Default to center position
|
||||
)
|
||||
} else {
|
||||
// Non-avatar prop
|
||||
(None, None, None)
|
||||
};
|
||||
|
||||
let is_droppable = req.droppable.unwrap_or(true);
|
||||
let is_public = req.public.unwrap_or(false);
|
||||
|
|
|
|||
|
|
@ -60,12 +60,11 @@ pub async fn create_realm(
|
|||
|
||||
/// Check if a realm slug is available.
|
||||
pub async fn is_slug_available(pool: &PgPool, slug: &str) -> Result<bool, AppError> {
|
||||
let exists: (bool,) = sqlx::query_as(
|
||||
r#"SELECT EXISTS(SELECT 1 FROM realm.realms WHERE slug = $1)"#,
|
||||
)
|
||||
.bind(slug)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
let exists: (bool,) =
|
||||
sqlx::query_as(r#"SELECT EXISTS(SELECT 1 FROM realm.realms WHERE slug = $1)"#)
|
||||
.bind(slug)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(!exists.0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,12 +116,13 @@ pub async fn is_scene_slug_available<'e>(
|
|||
realm_id: Uuid,
|
||||
slug: &str,
|
||||
) -> Result<bool, AppError> {
|
||||
let exists: (bool,) =
|
||||
sqlx::query_as(r#"SELECT EXISTS(SELECT 1 FROM realm.scenes WHERE realm_id = $1 AND slug = $2)"#)
|
||||
.bind(realm_id)
|
||||
.bind(slug)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
let exists: (bool,) = sqlx::query_as(
|
||||
r#"SELECT EXISTS(SELECT 1 FROM realm.scenes WHERE realm_id = $1 AND slug = $2)"#,
|
||||
)
|
||||
.bind(realm_id)
|
||||
.bind(slug)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
|
||||
Ok(!exists.0)
|
||||
}
|
||||
|
|
@ -294,7 +295,10 @@ pub async fn update_scene<'e>(
|
|||
param_idx += 1;
|
||||
}
|
||||
if req.dimension_mode.is_some() {
|
||||
set_clauses.push(format!("dimension_mode = ${}::realm.dimension_mode", param_idx));
|
||||
set_clauses.push(format!(
|
||||
"dimension_mode = ${}::realm.dimension_mode",
|
||||
param_idx
|
||||
));
|
||||
param_idx += 1;
|
||||
}
|
||||
if req.sort_order.is_some() {
|
||||
|
|
@ -317,7 +321,8 @@ pub async fn update_scene<'e>(
|
|||
s.is_hidden, s.created_at, s.updated_at, c.id as default_channel_id
|
||||
FROM realm.scenes s
|
||||
LEFT JOIN scene.instances c ON c.scene_id = s.id AND c.instance_type = 'public'
|
||||
WHERE s.id = $1"#.to_string()
|
||||
WHERE s.id = $1"#
|
||||
.to_string()
|
||||
} else {
|
||||
set_clauses.push("updated_at = now()".to_string());
|
||||
format!(
|
||||
|
|
@ -396,12 +401,11 @@ pub async fn get_next_sort_order<'e>(
|
|||
executor: impl PgExecutor<'e>,
|
||||
realm_id: Uuid,
|
||||
) -> Result<i32, AppError> {
|
||||
let result: (Option<i32>,) = sqlx::query_as(
|
||||
r#"SELECT MAX(sort_order) FROM realm.scenes WHERE realm_id = $1"#,
|
||||
)
|
||||
.bind(realm_id)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
let result: (Option<i32>,) =
|
||||
sqlx::query_as(r#"SELECT MAX(sort_order) FROM realm.scenes WHERE realm_id = $1"#)
|
||||
.bind(realm_id)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
|
||||
Ok(result.0.unwrap_or(0) + 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,12 +108,13 @@ pub async fn is_spot_slug_available<'e>(
|
|||
scene_id: Uuid,
|
||||
slug: &str,
|
||||
) -> Result<bool, AppError> {
|
||||
let exists: (bool,) =
|
||||
sqlx::query_as(r#"SELECT EXISTS(SELECT 1 FROM scene.spots WHERE scene_id = $1 AND slug = $2)"#)
|
||||
.bind(scene_id)
|
||||
.bind(slug)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
let exists: (bool,) = sqlx::query_as(
|
||||
r#"SELECT EXISTS(SELECT 1 FROM scene.spots WHERE scene_id = $1 AND slug = $2)"#,
|
||||
)
|
||||
.bind(scene_id)
|
||||
.bind(slug)
|
||||
.fetch_one(executor)
|
||||
.await?;
|
||||
|
||||
Ok(!exists.0)
|
||||
}
|
||||
|
|
@ -236,7 +237,8 @@ pub async fn update_spot<'e>(
|
|||
ST_AsText(destination_position) as destination_position_wkt,
|
||||
current_state, sort_order, is_visible, is_active,
|
||||
created_at, updated_at
|
||||
FROM scene.spots WHERE id = $1"#.to_string()
|
||||
FROM scene.spots WHERE id = $1"#
|
||||
.to_string()
|
||||
} else {
|
||||
set_clauses.push("updated_at = now()".to_string());
|
||||
format!(
|
||||
|
|
@ -293,10 +295,7 @@ pub async fn update_spot<'e>(
|
|||
}
|
||||
|
||||
/// Delete a spot.
|
||||
pub async fn delete_spot<'e>(
|
||||
executor: impl PgExecutor<'e>,
|
||||
spot_id: Uuid,
|
||||
) -> Result<(), AppError> {
|
||||
pub async fn delete_spot<'e>(executor: impl PgExecutor<'e>, spot_id: Uuid) -> Result<(), AppError> {
|
||||
let result = sqlx::query(r#"DELETE FROM scene.spots WHERE id = $1"#)
|
||||
.bind(spot_id)
|
||||
.execute(executor)
|
||||
|
|
|
|||
|
|
@ -293,8 +293,8 @@ pub async fn update_password(
|
|||
new_password: &str,
|
||||
) -> Result<(), AppError> {
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHasher,
|
||||
password_hash::{SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
|
@ -326,8 +326,8 @@ pub async fn update_password_conn(
|
|||
new_password: &str,
|
||||
) -> Result<(), AppError> {
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHasher,
|
||||
password_hash::{SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
|
@ -405,8 +405,8 @@ pub async fn create_user(
|
|||
password: &str,
|
||||
) -> Result<Uuid, AppError> {
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHasher,
|
||||
password_hash::{SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
|
@ -442,8 +442,8 @@ pub async fn create_user_conn(
|
|||
password: &str,
|
||||
) -> Result<Uuid, AppError> {
|
||||
use argon2::{
|
||||
password_hash::{rand_core::OsRng, SaltString},
|
||||
Argon2, PasswordHasher,
|
||||
password_hash::{SaltString, rand_core::OsRng},
|
||||
};
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
|
@ -473,7 +473,10 @@ pub async fn create_user_conn(
|
|||
/// Get a staff member by their user ID.
|
||||
///
|
||||
/// Returns the staff member with their user info joined.
|
||||
pub async fn get_staff_member(pool: &PgPool, user_id: Uuid) -> Result<Option<StaffMember>, AppError> {
|
||||
pub async fn get_staff_member(
|
||||
pool: &PgPool,
|
||||
user_id: Uuid,
|
||||
) -> Result<Option<StaffMember>, AppError> {
|
||||
let staff = sqlx::query_as::<_, StaffMember>(
|
||||
r#"
|
||||
SELECT
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue