152 lines
4.4 KiB
Rust
152 lines
4.4 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use time::OffsetDateTime;
|
|
|
|
use crate::ids::{InvitationId, PlatformApiKeyId, UserId, WorkspaceId};
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum UserStatus {
|
|
Active,
|
|
Disabled,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum MembershipRole {
|
|
Owner,
|
|
Admin,
|
|
Operator,
|
|
Viewer,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum InvitationStatus {
|
|
Pending,
|
|
Accepted,
|
|
Revoked,
|
|
Expired,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum PlatformApiKeyStatus {
|
|
Active,
|
|
Revoked,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum PlatformApiKeyScope {
|
|
Read,
|
|
Write,
|
|
Deploy,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct User {
|
|
pub id: UserId,
|
|
pub email: String,
|
|
pub display_name: String,
|
|
pub status: UserStatus,
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
pub created_at: OffsetDateTime,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct Membership {
|
|
pub workspace_id: WorkspaceId,
|
|
pub user_id: UserId,
|
|
pub role: MembershipRole,
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
pub created_at: OffsetDateTime,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct InvitationToken {
|
|
pub id: InvitationId,
|
|
pub workspace_id: WorkspaceId,
|
|
pub email: String,
|
|
pub role: MembershipRole,
|
|
pub status: InvitationStatus,
|
|
pub token_hash: String,
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
pub expires_at: OffsetDateTime,
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
pub created_at: OffsetDateTime,
|
|
}
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub struct PlatformApiKey {
|
|
pub id: PlatformApiKeyId,
|
|
pub workspace_id: WorkspaceId,
|
|
pub name: String,
|
|
pub prefix: String,
|
|
pub scopes: Vec<PlatformApiKeyScope>,
|
|
pub status: PlatformApiKeyStatus,
|
|
#[serde(with = "time::serde::rfc3339")]
|
|
pub created_at: OffsetDateTime,
|
|
#[serde(with = "time::serde::rfc3339::option")]
|
|
pub last_used_at: Option<OffsetDateTime>,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use serde_json::json;
|
|
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
|
|
|
use super::{PlatformApiKey, PlatformApiKeyScope, PlatformApiKeyStatus, User, UserStatus};
|
|
use crate::ids::{PlatformApiKeyId, UserId, WorkspaceId};
|
|
|
|
#[test]
|
|
fn user_serializes_created_at_as_rfc3339() {
|
|
let user = User {
|
|
id: UserId::new("user_01"),
|
|
email: "owner@example.com".to_owned(),
|
|
display_name: "Owner".to_owned(),
|
|
status: UserStatus::Active,
|
|
created_at: OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap(),
|
|
};
|
|
|
|
let value = serde_json::to_value(&user).unwrap();
|
|
|
|
assert_eq!(value["created_at"], json!("2026-03-25T12:00:00Z"));
|
|
}
|
|
|
|
#[test]
|
|
fn user_deserializes_created_at_from_rfc3339() {
|
|
let user: User = serde_json::from_value(json!({
|
|
"id": "user_01",
|
|
"email": "owner@example.com",
|
|
"display_name": "Owner",
|
|
"status": "active",
|
|
"created_at": "2026-03-25T12:00:00Z"
|
|
}))
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
user.created_at,
|
|
OffsetDateTime::parse("2026-03-25T12:00:00Z", &Rfc3339).unwrap()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn platform_api_key_serializes_timestamps_as_rfc3339() {
|
|
let api_key = PlatformApiKey {
|
|
id: PlatformApiKeyId::new("pk_01"),
|
|
workspace_id: WorkspaceId::new("ws_01"),
|
|
name: "Primary".to_owned(),
|
|
prefix: "crk_live".to_owned(),
|
|
scopes: vec![PlatformApiKeyScope::Read, PlatformApiKeyScope::Write],
|
|
status: PlatformApiKeyStatus::Active,
|
|
created_at: OffsetDateTime::parse("2026-03-25T12:01:00Z", &Rfc3339).unwrap(),
|
|
last_used_at: Some(OffsetDateTime::parse("2026-03-25T12:05:00Z", &Rfc3339).unwrap()),
|
|
};
|
|
|
|
let value = serde_json::to_value(&api_key).unwrap();
|
|
|
|
assert_eq!(value["created_at"], json!("2026-03-25T12:01:00Z"));
|
|
assert_eq!(value["last_used_at"], json!("2026-03-25T12:05:00Z"));
|
|
}
|
|
}
|