use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PlatformStats {
pub total_users: u64,
pub total_organizations: u64,
pub active_subscriptions: u64,
pub mrr_cents: u64,
pub recent_signups: u64,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SortOrder {
#[default]
Asc,
Desc,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListUsersParams {
pub search: Option<String>,
#[serde(default = "default_page")]
pub page: u32,
#[serde(default = "default_per_page")]
pub per_page: u32,
pub sort_by: Option<String>,
pub sort_order: Option<SortOrder>,
}
impl Default for ListUsersParams {
fn default() -> Self {
Self {
search: None,
page: default_page(),
per_page: default_per_page(),
sort_by: None,
sort_order: None,
}
}
}
fn default_page() -> u32 {
1
}
fn default_per_page() -> u32 {
20
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ListOrgsParams {
pub search: Option<String>,
#[serde(default = "default_page")]
pub page: u32,
#[serde(default = "default_per_page")]
pub per_page: u32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct UpdateUser {
pub name: Option<String>,
pub email_verified: Option<bool>,
pub locked: Option<bool>,
pub is_platform_admin: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PaginatedResult<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u32,
pub per_page: u32,
pub total_pages: u32,
}
impl<T> PaginatedResult<T> {
pub fn new(items: Vec<T>, total: u64, page: u32, per_page: u32) -> Self {
let total_pages = if per_page > 0 {
((total as f64) / (per_page as f64)).ceil() as u32
} else {
0
};
Self {
items,
total,
page,
per_page,
total_pages,
}
}
pub fn has_next(&self) -> bool {
self.page < self.total_pages
}
pub fn has_prev(&self) -> bool {
self.page > 1
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AuditLogParams {
pub user_id: Option<String>,
pub action: Option<String>,
pub from: Option<DateTime<Utc>>,
pub to: Option<DateTime<Utc>>,
#[serde(default = "default_page")]
pub page: u32,
#[serde(default = "default_per_page")]
pub per_page: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
pub id: String,
pub user_id: String,
pub action: String,
pub details: Option<String>,
pub ip_address: Option<String>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PlatformInviteStatus {
#[default]
Pending,
Accepted,
Revoked,
Expired,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformInvite {
pub id: String,
pub email: String,
pub plan_id: Option<String>,
pub trial_days: Option<u32>,
pub status: PlatformInviteStatus,
pub invited_by: String,
pub expires_at: DateTime<Utc>,
pub created_at: DateTime<Utc>,
pub accepted_at: Option<DateTime<Utc>>,
pub accepted_by_user_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreatePlatformInvite {
pub email: String,
pub plan_id: Option<String>,
pub trial_days: Option<u32>,
pub message: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ListPlatformInvitesParams {
pub status: Option<PlatformInviteStatus>,
pub search: Option<String>,
#[serde(default = "default_page")]
pub page: u32,
#[serde(default = "default_per_page")]
pub per_page: u32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformInviteConsumption {
pub invite: PlatformInvite,
pub plan_id: Option<String>,
pub trial_days: Option<u32>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_paginated_result() {
let result: PaginatedResult<i32> = PaginatedResult::new(vec![1, 2, 3], 100, 1, 10);
assert_eq!(result.total_pages, 10);
assert!(result.has_next());
assert!(!result.has_prev());
let result2: PaginatedResult<i32> = PaginatedResult::new(vec![1, 2, 3], 100, 10, 10);
assert!(!result2.has_next());
assert!(result2.has_prev());
}
#[test]
fn test_default_params() {
let params = ListUsersParams::default();
assert_eq!(params.page, 1);
assert_eq!(params.per_page, 20);
}
}