//! SSH key, OAuth code, issue, and issue comment models. use chrono::{DateTime, Utc}; use serde::Serialize; use sqlx::FromRow; use super::super::enums::CreatorTier; use super::super::id_types::{ GitRepoId, IssueCommentId, IssueId, IssueLabelId, OAuthCodeId, OAuthRefreshTokenId, SshKeyId, SyncAppId, UserId, }; use super::super::validated_types::{Email, Username}; use crate::currency::SettlementCurrency; /// An SSH public key registered by a user for git push access. #[derive(Debug, Clone, FromRow, Serialize)] pub struct DbSshKey { /// Database primary key. pub id: SshKeyId, /// User who owns this key. pub user_id: UserId, /// The SSH public key data (e.g., "ssh-ed25519 AAAA..."). pub public_key: String, /// SHA-256 fingerprint (e.g., "SHA256:abc..."). pub fingerprint: String, /// Human-readable label for the key (e.g., "laptop"). pub label: String, /// When the key was registered. pub created_at: DateTime, } /// An SSH key joined with its owner's username, for authorized_keys rebuild. #[derive(Debug, Clone, FromRow)] pub struct SshKeyWithUsername { /// SSH key primary key. pub id: SshKeyId, /// The SSH public key data. pub public_key: String, /// Owner's username. pub username: String, } /// User info returned by SSH key fingerprint lookup (for CLI auth). #[derive(Debug, Clone, FromRow, Serialize)] pub struct SshKeyUserLookup { pub user_id: UserId, pub username: Username, pub display_name: Option, pub email: Email, pub creator_tier: Option, pub can_create_projects: bool, pub suspended: bool, /// The currency this user is paid in, and so the currency every amount the /// CLI renders for them is denominated in. Carried on the login lookup /// because the CLI needs it before any dashboard call returns: a screen that /// waits for revenue data to learn the symbol renders the wrong one first. pub settlement_currency: SettlementCurrency, /// The creator's SSH console theme as a `makeover::ThemeSelection` string, /// or `None` where they have never chosen. Carried on the login lookup for /// the same reason as the currency: the CLI paints its first frame before /// any dashboard call returns, and a console that repaints once the theme /// arrives has already shown the wrong one. pub console_theme: Option, } /// An OAuth2 authorization code for PKCE flow. #[derive(Debug, Clone, FromRow)] #[allow(dead_code)] // Fields read via sqlx queries and in route handlers pub struct DbOAuthCode { pub id: OAuthCodeId, /// SHA-256 hex of the authorization code, never the plaintext. Stored and /// looked up by this hash (see `db::oauth`), so a DB read can't surface a /// live, redeemable code, same at-rest contract as refresh-token hashes. pub code: String, pub app_id: SyncAppId, pub user_id: UserId, pub code_challenge: String, pub code_challenge_method: String, pub redirect_uri: String, /// Space-delimited granted scope (e.g. `profile:read perks:read offline_access`). pub scope: String, pub expires_at: DateTime, pub used_at: Option>, pub created_at: DateTime, } /// A rotating, scoped OAuth refresh token. Stored as a SHA-256 hash; the /// plaintext only ever exists in the token response and the RP's store. #[derive(Debug, Clone, FromRow)] #[allow(dead_code)] // Fields read via sqlx queries and in route handlers pub struct DbOAuthRefreshToken { pub id: OAuthRefreshTokenId, pub token_hash: String, pub app_id: SyncAppId, pub user_id: UserId, pub key: String, pub scope: String, /// Stable across rotations, revoking the chain kills every descendant. pub chain_id: uuid::Uuid, pub expires_at: DateTime, pub used_at: Option>, pub revoked_at: Option>, /// Compared to `users.jwt_invalidated_at` so password change / suspend /// revokes the whole refresh lineage with no separate revocation system. pub issued_after: DateTime, pub created_at: DateTime, } // ── Git Issue models ── /// An issue filed against a git repository. #[derive(Debug, Clone, FromRow, Serialize)] pub struct DbIssue { pub id: IssueId, pub repo_id: GitRepoId, pub number: i32, pub author_user_id: UserId, pub title: String, pub body_markdown: String, pub body_html: String, pub status: super::super::IssueStatus, pub created_at: DateTime, pub updated_at: DateTime, /// Multithreaded forum thread mirroring this issue. Populated by the /// inbound issues handler when MT is configured; `None` otherwise. pub mt_thread_id: Option, } /// An issue with joined metadata for list display. #[derive(Debug, Clone, FromRow)] pub struct DbIssueWithMeta { pub id: IssueId, pub repo_id: GitRepoId, pub number: i32, pub author_user_id: UserId, pub title: String, pub status: super::super::IssueStatus, pub created_at: DateTime, pub updated_at: DateTime, pub author_username: String, pub comment_count: i64, } /// A comment on an issue. #[derive(Debug, Clone, FromRow, Serialize)] pub struct DbIssueComment { pub id: IssueCommentId, pub issue_id: IssueId, pub author_user_id: UserId, pub body_markdown: String, pub body_html: String, pub created_at: DateTime, } /// A comment with joined author username. #[derive(Debug, Clone, FromRow)] pub struct DbIssueCommentWithAuthor { pub id: IssueCommentId, pub issue_id: IssueId, pub author_user_id: UserId, pub body_markdown: String, pub body_html: String, pub created_at: DateTime, pub author_username: String, } /// A label that can be attached to issues within a repo. #[derive(Debug, Clone, FromRow, Serialize)] pub struct DbIssueLabel { pub id: IssueLabelId, pub repo_id: GitRepoId, pub name: String, pub color: String, }