Skip to main content

max / makenotwork

5.5 KB · 169 lines History Blame Raw
1 //! SSH key, OAuth code, issue, and issue comment models.
2
3 use chrono::{DateTime, Utc};
4 use serde::Serialize;
5 use sqlx::FromRow;
6
7 use super::super::enums::CreatorTier;
8 use super::super::id_types::{
9 GitRepoId, IssueCommentId, IssueId, IssueLabelId, OAuthCodeId, OAuthRefreshTokenId, SshKeyId,
10 SyncAppId, UserId,
11 };
12 use super::super::validated_types::{Email, Username};
13 use crate::currency::SettlementCurrency;
14
15 /// An SSH public key registered by a user for git push access.
16 #[derive(Debug, Clone, FromRow, Serialize)]
17 pub struct DbSshKey {
18 /// Database primary key.
19 pub id: SshKeyId,
20 /// User who owns this key.
21 pub user_id: UserId,
22 /// The SSH public key data (e.g., "ssh-ed25519 AAAA...").
23 pub public_key: String,
24 /// SHA-256 fingerprint (e.g., "SHA256:abc...").
25 pub fingerprint: String,
26 /// Human-readable label for the key (e.g., "laptop").
27 pub label: String,
28 /// When the key was registered.
29 pub created_at: DateTime<Utc>,
30 }
31
32 /// An SSH key joined with its owner's username, for authorized_keys rebuild.
33 #[derive(Debug, Clone, FromRow)]
34 pub struct SshKeyWithUsername {
35 /// SSH key primary key.
36 pub id: SshKeyId,
37 /// The SSH public key data.
38 pub public_key: String,
39 /// Owner's username.
40 pub username: String,
41 }
42
43 /// User info returned by SSH key fingerprint lookup (for CLI auth).
44 #[derive(Debug, Clone, FromRow, Serialize)]
45 pub struct SshKeyUserLookup {
46 pub user_id: UserId,
47 pub username: Username,
48 pub display_name: Option<String>,
49 pub email: Email,
50 pub creator_tier: Option<CreatorTier>,
51 pub can_create_projects: bool,
52 pub suspended: bool,
53 /// The currency this user is paid in, and so the currency every amount the
54 /// CLI renders for them is denominated in. Carried on the login lookup
55 /// because the CLI needs it before any dashboard call returns: a screen that
56 /// waits for revenue data to learn the symbol renders the wrong one first.
57 pub settlement_currency: SettlementCurrency,
58 }
59
60 /// An OAuth2 authorization code for PKCE flow.
61 #[derive(Debug, Clone, FromRow)]
62 #[allow(dead_code)] // Fields read via sqlx queries and in route handlers
63 pub struct DbOAuthCode {
64 pub id: OAuthCodeId,
65 /// SHA-256 hex of the authorization code, never the plaintext. Stored and
66 /// looked up by this hash (see `db::oauth`), so a DB read can't surface a
67 /// live, redeemable code, same at-rest contract as refresh-token hashes.
68 pub code: String,
69 pub app_id: SyncAppId,
70 pub user_id: UserId,
71 pub code_challenge: String,
72 pub code_challenge_method: String,
73 pub redirect_uri: String,
74 /// Space-delimited granted scope (e.g. `profile:read perks:read offline_access`).
75 pub scope: String,
76 pub expires_at: DateTime<Utc>,
77 pub used_at: Option<DateTime<Utc>>,
78 pub created_at: DateTime<Utc>,
79 }
80
81 /// A rotating, scoped OAuth refresh token. Stored as a SHA-256 hash; the
82 /// plaintext only ever exists in the token response and the RP's store.
83 #[derive(Debug, Clone, FromRow)]
84 #[allow(dead_code)] // Fields read via sqlx queries and in route handlers
85 pub struct DbOAuthRefreshToken {
86 pub id: OAuthRefreshTokenId,
87 pub token_hash: String,
88 pub app_id: SyncAppId,
89 pub user_id: UserId,
90 pub key: String,
91 pub scope: String,
92 /// Stable across rotations, revoking the chain kills every descendant.
93 pub chain_id: uuid::Uuid,
94 pub expires_at: DateTime<Utc>,
95 pub used_at: Option<DateTime<Utc>>,
96 pub revoked_at: Option<DateTime<Utc>>,
97 /// Compared to `users.jwt_invalidated_at` so password change / suspend
98 /// revokes the whole refresh lineage with no separate revocation system.
99 pub issued_after: DateTime<Utc>,
100 pub created_at: DateTime<Utc>,
101 }
102
103 // ── Git Issue models ──
104
105 /// An issue filed against a git repository.
106 #[derive(Debug, Clone, FromRow, Serialize)]
107 pub struct DbIssue {
108 pub id: IssueId,
109 pub repo_id: GitRepoId,
110 pub number: i32,
111 pub author_user_id: UserId,
112 pub title: String,
113 pub body_markdown: String,
114 pub body_html: String,
115 pub status: super::super::IssueStatus,
116 pub created_at: DateTime<Utc>,
117 pub updated_at: DateTime<Utc>,
118 /// Multithreaded forum thread mirroring this issue. Populated by the
119 /// inbound issues handler when MT is configured; `None` otherwise.
120 pub mt_thread_id: Option<uuid::Uuid>,
121 }
122
123 /// An issue with joined metadata for list display.
124 #[derive(Debug, Clone, FromRow)]
125 pub struct DbIssueWithMeta {
126 pub id: IssueId,
127 pub repo_id: GitRepoId,
128 pub number: i32,
129 pub author_user_id: UserId,
130 pub title: String,
131 pub status: super::super::IssueStatus,
132 pub created_at: DateTime<Utc>,
133 pub updated_at: DateTime<Utc>,
134 pub author_username: String,
135 pub comment_count: i64,
136 }
137
138 /// A comment on an issue.
139 #[derive(Debug, Clone, FromRow, Serialize)]
140 pub struct DbIssueComment {
141 pub id: IssueCommentId,
142 pub issue_id: IssueId,
143 pub author_user_id: UserId,
144 pub body_markdown: String,
145 pub body_html: String,
146 pub created_at: DateTime<Utc>,
147 }
148
149 /// A comment with joined author username.
150 #[derive(Debug, Clone, FromRow)]
151 pub struct DbIssueCommentWithAuthor {
152 pub id: IssueCommentId,
153 pub issue_id: IssueId,
154 pub author_user_id: UserId,
155 pub body_markdown: String,
156 pub body_html: String,
157 pub created_at: DateTime<Utc>,
158 pub author_username: String,
159 }
160
161 /// A label that can be attached to issues within a repo.
162 #[derive(Debug, Clone, FromRow, Serialize)]
163 pub struct DbIssueLabel {
164 pub id: IssueLabelId,
165 pub repo_id: GitRepoId,
166 pub name: String,
167 pub color: String,
168 }
169