1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3use uuid::Uuid;
4
5use authx_core::{
6 error::Result,
7 models::{
8 ApiKey, AuditLog, CreateApiKey, CreateAuditLog, CreateCredential, CreateInvite, CreateOrg,
9 CreateSession, CreateUser, Credential, CredentialKind, Invite, Membership, OAuthAccount,
10 Organization, Role, Session, UpdateUser, UpsertOAuthAccount, User,
11 },
12};
13
14#[async_trait]
15pub trait UserRepository: Send + Sync + 'static {
16 async fn find_by_id(&self, id: Uuid) -> Result<Option<User>>;
17 async fn find_by_email(&self, email: &str) -> Result<Option<User>>;
18 async fn find_by_username(&self, username: &str) -> Result<Option<User>>;
19 async fn list(&self, offset: u32, limit: u32) -> Result<Vec<User>>;
20 async fn create(&self, data: CreateUser) -> Result<User>;
21 async fn update(&self, id: Uuid, data: UpdateUser) -> Result<User>;
22 async fn delete(&self, id: Uuid) -> Result<()>;
23}
24
25#[async_trait]
26pub trait SessionRepository: Send + Sync + 'static {
27 async fn create(&self, data: CreateSession) -> Result<Session>;
28 async fn find_by_token_hash(&self, hash: &str) -> Result<Option<Session>>;
29 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<Session>>;
30 async fn invalidate(&self, session_id: Uuid) -> Result<()>;
31 async fn invalidate_all_for_user(&self, user_id: Uuid) -> Result<()>;
32 async fn set_org(&self, session_id: Uuid, org_id: Option<Uuid>) -> Result<Session>;
33}
34
35#[async_trait]
36pub trait CredentialRepository: Send + Sync + 'static {
37 async fn create(&self, data: CreateCredential) -> Result<Credential>;
38 async fn find_password_hash(&self, user_id: Uuid) -> Result<Option<String>>;
39 async fn find_by_user_and_kind(
40 &self,
41 user_id: Uuid,
42 kind: CredentialKind,
43 ) -> Result<Option<Credential>>;
44 async fn delete_by_user_and_kind(&self, user_id: Uuid, kind: CredentialKind) -> Result<()>;
45}
46
47#[async_trait]
48pub trait OrgRepository: Send + Sync + 'static {
49 async fn create(&self, data: CreateOrg) -> Result<Organization>;
50 async fn find_by_id(&self, id: Uuid) -> Result<Option<Organization>>;
51 async fn find_by_slug(&self, slug: &str) -> Result<Option<Organization>>;
52 async fn add_member(&self, org_id: Uuid, user_id: Uuid, role_id: Uuid) -> Result<Membership>;
53 async fn remove_member(&self, org_id: Uuid, user_id: Uuid) -> Result<()>;
54 async fn get_members(&self, org_id: Uuid) -> Result<Vec<Membership>>;
55 async fn find_roles(&self, org_id: Uuid) -> Result<Vec<Role>>;
56 async fn create_role(
57 &self,
58 org_id: Uuid,
59 name: String,
60 permissions: Vec<String>,
61 ) -> Result<Role>;
62 async fn update_member_role(
63 &self,
64 org_id: Uuid,
65 user_id: Uuid,
66 role_id: Uuid,
67 ) -> Result<Membership>;
68}
69
70#[async_trait]
71pub trait AuditLogRepository: Send + Sync + 'static {
72 async fn append(&self, entry: CreateAuditLog) -> Result<AuditLog>;
73 async fn find_by_user(&self, user_id: Uuid, limit: u32) -> Result<Vec<AuditLog>>;
74 async fn find_by_org(&self, org_id: Uuid, limit: u32) -> Result<Vec<AuditLog>>;
75}
76
77#[async_trait]
78pub trait ApiKeyRepository: Send + Sync + 'static {
79 async fn create(&self, data: CreateApiKey) -> Result<ApiKey>;
80 async fn find_by_hash(&self, key_hash: &str) -> Result<Option<ApiKey>>;
81 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<ApiKey>>;
82 async fn revoke(&self, key_id: Uuid, user_id: Uuid) -> Result<()>;
83 async fn touch_last_used(&self, key_id: Uuid, at: DateTime<Utc>) -> Result<()>;
84}
85
86#[async_trait]
87pub trait OAuthAccountRepository: Send + Sync + 'static {
88 async fn upsert(&self, data: UpsertOAuthAccount) -> Result<OAuthAccount>;
89 async fn find_by_provider(
90 &self,
91 provider: &str,
92 provider_user_id: &str,
93 ) -> Result<Option<OAuthAccount>>;
94 async fn find_by_user(&self, user_id: Uuid) -> Result<Vec<OAuthAccount>>;
95 async fn delete(&self, id: Uuid) -> Result<()>;
96}
97
98#[async_trait]
99pub trait InviteRepository: Send + Sync + 'static {
100 async fn create(&self, data: CreateInvite) -> Result<Invite>;
101 async fn find_by_token_hash(&self, hash: &str) -> Result<Option<Invite>>;
102 async fn accept(&self, invite_id: Uuid) -> Result<Invite>;
103 async fn delete_expired(&self) -> Result<u64>;
104}
105
106pub trait StorageAdapter:
108 UserRepository
109 + SessionRepository
110 + CredentialRepository
111 + OrgRepository
112 + AuditLogRepository
113 + ApiKeyRepository
114 + OAuthAccountRepository
115 + InviteRepository
116 + Clone
117 + Send
118 + Sync
119 + 'static
120{
121}
122
123impl<T> StorageAdapter for T where
124 T: UserRepository
125 + SessionRepository
126 + CredentialRepository
127 + OrgRepository
128 + AuditLogRepository
129 + ApiKeyRepository
130 + OAuthAccountRepository
131 + InviteRepository
132 + Clone
133 + Send
134 + Sync
135 + 'static
136{
137}