142 lines
4.4 KiB
Rust
142 lines
4.4 KiB
Rust
use chrono::{DateTime, Utc};
|
|
use serde::{Deserialize, Serialize};
|
|
use sqlx::{FromRow, PgPool};
|
|
use uuid::Uuid;
|
|
|
|
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
|
pub struct CustomerProfile {
|
|
pub id: Uuid,
|
|
pub user_id: Uuid,
|
|
pub first_name: Option<String>,
|
|
pub last_name: Option<String>,
|
|
pub phone: Option<String>,
|
|
pub city: Option<String>,
|
|
pub area: Option<String>,
|
|
pub preferred_professions: Option<Vec<String>>,
|
|
pub active_requirement_count: i32,
|
|
pub status: String,
|
|
pub bio: Option<String>,
|
|
pub custom_data: Option<serde_json::Value>,
|
|
pub created_at: DateTime<Utc>,
|
|
pub updated_at: DateTime<Utc>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct UpsertCustomerProfilePayload {
|
|
pub first_name: Option<String>,
|
|
pub last_name: Option<String>,
|
|
pub phone: Option<String>,
|
|
pub city: Option<String>,
|
|
pub area: Option<String>,
|
|
pub preferred_professions: Option<Vec<String>>,
|
|
pub bio: Option<String>,
|
|
pub custom_data: Option<serde_json::Value>,
|
|
}
|
|
|
|
pub struct CustomerRepository;
|
|
|
|
impl CustomerRepository {
|
|
pub async fn get_by_user_id(
|
|
pool: &PgPool,
|
|
user_id: Uuid,
|
|
) -> Result<Option<CustomerProfile>, sqlx::Error> {
|
|
let profile = sqlx::query_as::<_, CustomerProfile>(
|
|
r#"
|
|
SELECT
|
|
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
|
|
active_requirement_count, status, bio, custom_data,
|
|
created_at, updated_at
|
|
FROM customer_profiles
|
|
WHERE user_id = $1
|
|
"#,
|
|
)
|
|
.bind(user_id)
|
|
.fetch_optional(pool)
|
|
.await?;
|
|
|
|
Ok(profile)
|
|
}
|
|
|
|
pub async fn upsert(
|
|
pool: &PgPool,
|
|
user_id: Uuid,
|
|
payload: UpsertCustomerProfilePayload,
|
|
) -> Result<CustomerProfile, sqlx::Error> {
|
|
let profile = sqlx::query_as::<_, CustomerProfile>(
|
|
r#"
|
|
INSERT INTO customer_profiles (
|
|
user_id, first_name, last_name, phone, city, area, preferred_professions, bio, custom_data, status
|
|
)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, 'PENDING')
|
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
first_name = EXCLUDED.first_name,
|
|
last_name = EXCLUDED.last_name,
|
|
phone = EXCLUDED.phone,
|
|
city = EXCLUDED.city,
|
|
area = EXCLUDED.area,
|
|
preferred_professions = EXCLUDED.preferred_professions,
|
|
bio = EXCLUDED.bio,
|
|
custom_data = EXCLUDED.custom_data,
|
|
status = CASE
|
|
WHEN customer_profiles.status = 'APPROVED' THEN 'APPROVED'
|
|
ELSE 'PENDING'
|
|
END,
|
|
updated_at = NOW()
|
|
RETURNING
|
|
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
|
|
active_requirement_count, status, bio, custom_data,
|
|
created_at, updated_at
|
|
"#,
|
|
)
|
|
.bind(user_id)
|
|
.bind(payload.first_name)
|
|
.bind(payload.last_name)
|
|
.bind(payload.phone)
|
|
.bind(payload.city)
|
|
.bind(payload.area)
|
|
.bind(payload.preferred_professions.unwrap_or_default())
|
|
.bind(payload.bio)
|
|
.bind(payload.custom_data)
|
|
.fetch_one(pool)
|
|
.await?;
|
|
|
|
Ok(profile)
|
|
}
|
|
|
|
pub async fn update_active_requirement_count(
|
|
pool: &PgPool,
|
|
id: Uuid,
|
|
delta: i32,
|
|
) -> Result<(), sqlx::Error> {
|
|
sqlx::query(
|
|
"UPDATE customer_profiles SET active_requirement_count = active_requirement_count + $1 WHERE id = $2",
|
|
)
|
|
.bind(delta)
|
|
.bind(id)
|
|
.execute(pool)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn submit_for_verification(
|
|
pool: &PgPool,
|
|
user_id: Uuid,
|
|
) -> Result<CustomerProfile, sqlx::Error> {
|
|
let profile = sqlx::query_as::<_, CustomerProfile>(
|
|
r#"
|
|
UPDATE customer_profiles
|
|
SET status = 'PENDING_REVIEW', updated_at = NOW()
|
|
WHERE user_id = $1
|
|
RETURNING
|
|
id, user_id, first_name, last_name, phone, city, area, preferred_professions,
|
|
active_requirement_count, status, bio, custom_data,
|
|
created_at, updated_at
|
|
"#,
|
|
)
|
|
.bind(user_id)
|
|
.fetch_one(pool)
|
|
.await?;
|
|
|
|
Ok(profile)
|
|
}
|
|
}
|