use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; // ============================================================================ // API Response Types // ============================================================================ #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApiResponse { pub success: bool, pub data: Option, pub error: Option, pub message: Option, } /// Format backend error payloads into a readable string. pub fn api_error_detail(error: &Option) -> String { error .as_ref() .map(String::from) .unwrap_or_else(|| "Unknown backend error".to_string()) } // ============================================================================ // Authentication // ============================================================================ #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LoginRequest { pub method: String, #[serde(skip_serializing_if = "Option::is_none")] pub username: Option, #[serde(skip_serializing_if = "Option::is_none")] pub password: Option, #[serde(skip_serializing_if = "Option::is_none")] pub pin: Option, #[serde(skip_serializing_if = "Option::is_none")] pub login_string: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LoginResponse { pub success: bool, pub token: String, pub user: UserInfo, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct UserInfo { pub id: i32, pub username: String, pub role: String, pub power: i32, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SessionStatus { pub valid: bool, pub user: Option, pub expires_at: Option>, pub message: Option, } // ============================================================================ // Permissions // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PermissionsResponse { pub user: UserInfo, pub user_settings_access: String, pub permissions: serde_json::Value, // Flexible permissions structure pub security_clearance: Option, } // ============================================================================ // Preferences // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PreferencesRequest { pub action: String, // "get", "set", "reset" #[serde(skip_serializing_if = "Option::is_none")] pub user_id: Option, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "preferences")] pub preferences: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PreferencesResponse { pub user_id: i32, pub preferences: serde_json::Value, } // ============================================================================ // Query Operations // ============================================================================ #[derive(Debug, Clone, Serialize, Deserialize)] pub struct QueryRequest { pub action: String, // "select", "insert", "update", "delete", "count" pub table: String, #[serde(skip_serializing_if = "Option::is_none")] pub columns: Option>, #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "data")] pub data: Option, #[serde(skip_serializing_if = "Option::is_none")] pub r#where: Option, #[serde(skip_serializing_if = "Option::is_none")] pub filter: Option, #[serde(skip_serializing_if = "Option::is_none")] pub order_by: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub limit: Option, #[serde(skip_serializing_if = "Option::is_none")] pub offset: Option, #[serde(skip_serializing_if = "Option::is_none")] pub joins: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OrderBy { pub column: String, pub direction: String, // "ASC" or "DESC" } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Join { pub table: String, pub on: String, #[serde(rename = "type")] pub join_type: String, // "INNER", "LEFT", "RIGHT" - serialized as "type" for API } // ============================================================================ // Asset Models // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Asset { pub id: Option, pub asset_tag: String, pub asset_numeric_id: Option, pub asset_type: String, // "N", "T", "C" pub name: String, pub description: Option, pub category_id: Option, pub zone_id: Option, pub zone_plus: Option, // "Exact", "Clarify", "Deployed" pub zone_note: Option, pub manufacturer: Option, pub model: Option, pub serial_number: Option, pub status: String, // "Good", "Faulty", "Scrapped", "Missing" pub price: Option, pub purchase_date: Option, pub warranty_expiry: Option, pub supplier_id: Option, pub lendable: bool, pub lending_status: Option, // "Available", "Borrowed", "Deployed", "Overdue" pub asset_image: Option, pub notes: Option, pub created_by: Option, pub created_date: Option>, pub last_modified_by: Option, pub last_modified_date: Option>, } // ============================================================================ // Borrower Models // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Borrower { pub id: Option, pub borrower_code: String, pub name: String, pub email: Option, pub phone: Option, pub borrower_type: String, // "Student", "Faculty", "Staff", "External" pub department: Option, pub banned: bool, pub unban_fine: Option, pub ban_reason: Option, pub notes: Option, } // ============================================================================ // Category & Zone Models // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Category { pub id: Option, pub category_code: String, pub name: String, pub description: Option, } #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Zone { pub id: Option, pub zone_code: String, pub name: String, pub parent_zone_id: Option, pub level: i32, pub description: Option, } // ============================================================================ // Lending History // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct LendingHistory { pub id: Option, pub asset_id: i32, pub borrower_id: i32, pub checkout_date: DateTime, pub due_date: String, pub return_date: Option>, pub status: String, // "Active", "Returned", "Overdue", "Lost" pub checkout_condition: Option, pub return_condition: Option, pub notes: Option, pub checked_out_by: Option, pub checked_in_by: Option, } // ============================================================================ // Issue Tracker // ============================================================================ #[allow(dead_code)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Issue { pub id: Option, pub issue_type: String, // "Asset Issue", "Borrower Issue", "System Issue" pub asset_id: Option, pub borrower_id: Option, pub title: String, pub description: Option, pub severity: String, // "Low", "Medium", "High", "Critical" pub priority: String, // "Low", "Medium", "High", "Critical" pub status: String, // "Open", "In Progress", "On Hold", "Resolved", "Closed" pub solution: Option, pub solution_plus: Option, pub auto_detected: bool, pub detection_trigger: Option, pub reported_by: Option, pub reported_date: Option>, pub resolved_by: Option, pub resolved_date: Option>, } // ============================================================================ // Dashboard Stats // ============================================================================ #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct DashboardStats { pub total_assets: i32, pub okay_items: i32, // All items with status "Good" pub attention_items: i32, // Faulty, Missing, Overdue, Attention, etc. }