1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use uuid::Uuid;
4
5use authx_core::{
6 error::Result,
7 models::{
8 ApiKey, AuditLog, AuthorizationCode, CreateApiKey, CreateAuditLog, CreateAuthorizationCode,
9 CreateCredential, CreateDeviceCode, CreateInvite, CreateOidcClient,
10 CreateOidcFederationProvider, CreateOidcToken, CreateOrg, CreateSession, CreateUser,
11 Credential, CredentialKind, DeviceCode, Invite, Membership, OAuthAccount, OidcClient,
12 OidcFederationProvider, OidcToken, Organization, Role, Session, UpdateUser,
13 UpsertOAuthAccount, User,
14 },
15};
16
17#[async_trait]
18pub trait UserRepository: Send + Sync + 'static {
19 async fn find_by_id(&self, id: Uuid) -> Result<Option<User>>;
20 async fn find_by_email(&self, email: &str) -> Result<Option<User>>;
21 async fn find_by_username(&self, username: &str) -> Result<Option<User>>;
22 async fn list(&self, offset: u32, limit: u32) -> Result<Vec<User>>;
23 async fn create(&self, data: CreateUser) -> Result<User>;
24 async fn update(&self, id: Uuid, data: UpdateUser) -> Result<User>;
25 async fn delete(&self, id: Uuid) -> Result<()>;
26}
27
28#[async_trait]
29pub trait SessionRepository: Send + Sync + 'static {
30 async fn create(&self, data: CreateSession) -> Result<Session>;
31 async fn find_by_token_hash(&self, hash: &str) -> Result<Option<Session>>;
32 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<Session>>;
33 async fn invalidate(&self, session_id: Uuid) -> Result<()>;
34 async fn invalidate_all_for_user(&self, user_id: Uuid) -> Result<()>;
35 async fn set_org(&self, session_id: Uuid, org_id: Option<Uuid>) -> Result<Session>;
36}
37
38#[async_trait]
39pub trait CredentialRepository: Send + Sync + 'static {
40 async fn create(&self, data: CreateCredential) -> Result<Credential>;
41 async fn find_password_hash(&self, user_id: Uuid) -> Result<Option<String>>;
42 async fn find_by_user_and_kind(
43 &self,
44 user_id: Uuid,
45 kind: CredentialKind,
46 ) -> Result<Option<Credential>>;
47 async fn delete_by_user_and_kind(&self, user_id: Uuid, kind: CredentialKind) -> Result<()>;
48}
49
50#[async_trait]
51pub trait OrgRepository: Send + Sync + 'static {
52 async fn create(&self, data: CreateOrg) -> Result<Organization>;
53 async fn find_by_id(&self, id: Uuid) -> Result<Option<Organization>>;
54 async fn find_by_slug(&self, slug: &str) -> Result<Option<Organization>>;
55 async fn add_member(&self, org_id: Uuid, user_id: Uuid, role_id: Uuid) -> Result<Membership>;
56 async fn remove_member(&self, org_id: Uuid, user_id: Uuid) -> Result<()>;
57 async fn get_members(&self, org_id: Uuid) -> Result<Vec<Membership>>;
58 async fn find_roles(&self, org_id: Uuid) -> Result<Vec<Role>>;
59 async fn create_role(
60 &self,
61 org_id: Uuid,
62 name: String,
63 permissions: Vec<String>,
64 ) -> Result<Role>;
65 async fn update_member_role(
66 &self,
67 org_id: Uuid,
68 user_id: Uuid,
69 role_id: Uuid,
70 ) -> Result<Membership>;
71}
72
73#[async_trait]
74pub trait AuditLogRepository: Send + Sync + 'static {
75 async fn append(&self, entry: CreateAuditLog) -> Result<AuditLog>;
76 async fn find_by_user(&self, user_id: Uuid, limit: u32) -> Result<Vec<AuditLog>>;
77 async fn find_by_org(&self, org_id: Uuid, limit: u32) -> Result<Vec<AuditLog>>;
78}
79
80#[async_trait]
81pub trait ApiKeyRepository: Send + Sync + 'static {
82 async fn create(&self, data: CreateApiKey) -> Result<ApiKey>;
83 async fn find_by_hash(&self, key_hash: &str) -> Result<Option<ApiKey>>;
84 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<ApiKey>>;
85 async fn revoke(&self, key_id: Uuid, user_id: Uuid) -> Result<()>;
86 async fn touch_last_used(&self, key_id: Uuid, at: DateTime<Utc>) -> Result<()>;
87}
88
89#[async_trait]
90pub trait OAuthAccountRepository: Send + Sync + 'static {
91 async fn upsert(&self, data: UpsertOAuthAccount) -> Result<OAuthAccount>;
92 async fn find_by_provider(
93 &self,
94 provider: &str,
95 provider_user_id: &str,
96 ) -> Result<Option<OAuthAccount>>;
97 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<OAuthAccount>>;
98 async fn delete(&self, id: Uuid) -> Result<()>;
99}
100
101#[async_trait]
102pub trait InviteRepository: Send + Sync + 'static {
103 async fn create(&self, data: CreateInvite) -> Result<Invite>;
104 async fn find_by_token_hash(&self, hash: &str) -> Result<Option<Invite>>;
105 async fn accept(&self, invite_id: Uuid) -> Result<Invite>;
106 async fn delete_expired(&self) -> Result<u64>;
107}
108
109#[async_trait]
112pub trait OidcClientRepository: Send + Sync + 'static {
113 async fn create(&self, data: CreateOidcClient) -> Result<OidcClient>;
114 async fn find_by_client_id(&self, client_id: &str) -> Result<Option<OidcClient>>;
115 async fn list(&self, offset: u32, limit: u32) -> Result<Vec<OidcClient>>;
116}
117
118#[async_trait]
119pub trait AuthorizationCodeRepository: Send + Sync + 'static {
120 async fn create(&self, data: CreateAuthorizationCode) -> Result<AuthorizationCode>;
121 async fn find_by_code_hash(&self, hash: &str) -> Result<Option<AuthorizationCode>>;
122 async fn mark_used(&self, id: Uuid) -> Result<()>;
123 async fn delete_expired(&self) -> Result<u64>;
124}
125
126#[async_trait]
127pub trait OidcTokenRepository: Send + Sync + 'static {
128 async fn create(&self, data: CreateOidcToken) -> Result<OidcToken>;
129 async fn find_by_token_hash(&self, hash: &str) -> Result<Option<OidcToken>>;
130 async fn revoke(&self, id: Uuid) -> Result<()>;
131 async fn revoke_all_for_user_client(&self, user_id: Uuid, client_id: &str) -> Result<()>;
132}
133
134#[async_trait]
135pub trait OidcFederationProviderRepository: Send + Sync + 'static {
136 async fn create(&self, data: CreateOidcFederationProvider) -> Result<OidcFederationProvider>;
137 async fn find_by_id(&self, id: Uuid) -> Result<Option<OidcFederationProvider>>;
138 async fn find_by_name(&self, name: &str) -> Result<Option<OidcFederationProvider>>;
139 async fn list_enabled(&self) -> Result<Vec<OidcFederationProvider>>;
140}
141
142#[async_trait]
145pub trait DeviceCodeRepository: Send + Sync + 'static {
146 async fn create(&self, data: CreateDeviceCode) -> Result<DeviceCode>;
147 async fn find_by_device_code_hash(&self, hash: &str) -> Result<Option<DeviceCode>>;
148 async fn find_by_user_code_hash(&self, hash: &str) -> Result<Option<DeviceCode>>;
149 async fn authorize(&self, id: Uuid, user_id: Uuid) -> Result<()>;
150 async fn deny(&self, id: Uuid) -> Result<()>;
151 async fn update_last_polled(&self, id: Uuid, interval_secs: u32) -> Result<()>;
152 async fn delete(&self, id: Uuid) -> Result<()>;
153 async fn delete_expired(&self) -> Result<u64>;
154 async fn list_by_client(
155 &self,
156 client_id: &str,
157 offset: u32,
158 limit: u32,
159 ) -> Result<Vec<DeviceCode>>;
160}
161
162pub trait StorageAdapter:
164 UserRepository
165 + SessionRepository
166 + CredentialRepository
167 + OrgRepository
168 + AuditLogRepository
169 + ApiKeyRepository
170 + OAuthAccountRepository
171 + InviteRepository
172 + OidcClientRepository
173 + AuthorizationCodeRepository
174 + OidcTokenRepository
175 + OidcFederationProviderRepository
176 + DeviceCodeRepository
177 + Clone
178 + Send
179 + Sync
180 + 'static
181{
182}
183
184impl<T> StorageAdapter for T where
185 T: UserRepository
186 + SessionRepository
187 + CredentialRepository
188 + OrgRepository
189 + AuditLogRepository
190 + ApiKeyRepository
191 + OAuthAccountRepository
192 + InviteRepository
193 + OidcClientRepository
194 + AuthorizationCodeRepository
195 + OidcTokenRepository
196 + OidcFederationProviderRepository
197 + DeviceCodeRepository
198 + Clone
199 + Send
200 + Sync
201 + 'static
202{
203}