Skip to main content

max / makenotwork

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