1use std::collections::HashMap;
2use std::path::Path;
3
4use chrono::{DateTime, Utc};
5use crate_meta::CrateMeta;
6use kellnr_common::account_name::{GroupName, UserName};
7use kellnr_common::canonical_name::CanonicalName;
8use kellnr_common::crate_data::CrateData;
9use kellnr_common::crate_dependents::CrateDependents;
10use kellnr_common::crate_overview::CrateOverview;
11use kellnr_common::cratesio_prefetch_msg::CratesioPrefetchMsg;
12use kellnr_common::index_metadata::IndexMetadata;
13use kellnr_common::original_name::OriginalName;
14use kellnr_common::plain_token::PlainToken;
15use kellnr_common::prefetch::Prefetch;
16use kellnr_common::publish_metadata::PublishMetadata;
17use kellnr_common::version::Version;
18use kellnr_common::webhook::{Webhook, WebhookEvent, WebhookQueue};
19use sea_orm::prelude::async_trait::async_trait;
20use serde::{Deserialize, Serialize};
21
22use crate::error::DbError;
23use crate::{
24 AuthToken, AuthTokenId, CrateId, DocQueueEntry, Group, ToolchainTargetStatus, User, UserFlags,
25 crate_meta,
26};
27
28pub type DbResult<T> = Result<T, DbError>;
29
30#[derive(Debug, PartialEq, Eq)]
31pub enum PrefetchState {
32 UpToDate {
35 etag: String,
36 last_modified: String,
37 },
38 NeedsUpdate(Prefetch),
39 NotFound,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct CratesioVersionMeta {
45 pub cksum: String,
46 pub license: Option<String>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53pub enum CrateVisibility {
54 All,
56 User(UserName),
59 Unrestricted,
61}
62
63#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
65#[serde(rename_all = "lowercase")]
66pub enum CrateSort {
67 #[default]
69 Name,
70 Updated,
72 Downloads,
74}
75
76#[derive(Debug, Clone, Default, PartialEq, Eq)]
80pub struct CrateTagFilter {
81 pub keyword: Option<String>,
82 pub category: Option<String>,
83}
84
85impl CrateTagFilter {
86 pub fn is_empty(&self) -> bool {
87 self.keyword.is_none() && self.category.is_none()
88 }
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct SessionInfo {
94 pub name: UserName,
95 pub is_admin: bool,
96 pub is_read_only: bool,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct OAuth2StateData {
102 pub state: String,
103 pub pkce_verifier: String,
104 pub nonce: String,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
109pub struct ToolchainComponentInfo {
110 pub name: String,
112 pub storage_path: String,
114 pub hash: String,
116 pub size: i64,
118}
119
120impl From<kellnr_entity::toolchain_component::Model> for ToolchainComponentInfo {
121 fn from(c: kellnr_entity::toolchain_component::Model) -> Self {
122 Self {
123 name: c.name,
124 storage_path: c.storage_path,
125 hash: c.hash,
126 size: c.size,
127 }
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
133pub struct ToolchainTargetInfo {
134 pub id: i64,
136 pub target: String,
138 pub storage_path: String,
140 pub hash: String,
142 pub size: i64,
144 pub status: ToolchainTargetStatus,
146 pub components: Vec<ToolchainComponentInfo>,
148}
149
150#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
152pub struct ToolchainWithTargets {
153 pub id: i64,
155 pub name: String,
157 pub version: String,
159 pub date: String,
161 pub channel: Option<String>,
163 pub created: String,
165 pub targets: Vec<ToolchainTargetInfo>,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
171pub struct ChannelInfo {
172 pub name: String,
174 pub version: String,
176 pub date: String,
178}
179
180#[cfg_attr(feature = "mock", mockall::automock)]
181#[async_trait]
182pub trait DbProvider: Send + Sync {
183 async fn get_last_updated_crate(
184 &self,
185 visibility: &CrateVisibility,
186 ) -> DbResult<Option<(OriginalName, Version)>>;
187 async fn authenticate_user(&self, name: &UserName, pwd: &str) -> DbResult<User>;
188 async fn increase_download_counter(
189 &self,
190 crate_name: &CanonicalName,
191 crate_version: &Version,
192 ) -> DbResult<()>;
193 async fn increase_cached_download_counter(
194 &self,
195 crate_name: &CanonicalName,
196 crate_version: &Version,
197 ) -> DbResult<()>;
198 async fn increase_download_counter_by(
199 &self,
200 crate_name: &CanonicalName,
201 crate_version: &Version,
202 count: u64,
203 ) -> DbResult<()>;
204 async fn increase_cached_download_counter_by(
205 &self,
206 crate_name: &CanonicalName,
207 crate_version: &Version,
208 count: u64,
209 ) -> DbResult<()>;
210 async fn validate_session(&self, session_token: &PlainToken) -> DbResult<SessionInfo>;
211 async fn delete_expired_sessions(&self) -> DbResult<u64>;
214 async fn add_session_token(&self, name: &UserName, session_token: &PlainToken) -> DbResult<()>;
215 async fn delete_user_sessions(&self, user_name: &UserName) -> DbResult<u64>;
217 async fn delete_other_user_sessions(
220 &self,
221 user_name: &UserName,
222 keep_session_token: &PlainToken,
223 ) -> DbResult<u64>;
224 async fn add_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<()>;
225 async fn add_owner(&self, crate_name: &CanonicalName, owner: &UserName) -> DbResult<()>;
228 async fn is_download_restricted(&self, crate_name: &CanonicalName) -> DbResult<bool>;
229 async fn change_download_restricted(
230 &self,
231 crate_name: &CanonicalName,
232 restricted: bool,
233 ) -> DbResult<()>;
234 async fn is_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<bool>;
235 async fn is_owner(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<bool>;
236 async fn get_crate_id(&self, crate_name: &CanonicalName) -> DbResult<Option<CrateId>>;
237 async fn get_crate_owners(&self, crate_name: &CanonicalName) -> DbResult<Vec<User>>;
238 async fn get_crate_users(&self, crate_name: &CanonicalName) -> DbResult<Vec<User>>;
239 async fn get_crate_versions(&self, crate_name: &CanonicalName) -> DbResult<Vec<Version>>;
240 async fn delete_session_token(&self, session_token: &PlainToken) -> DbResult<()>;
241 async fn delete_user(&self, user_name: &UserName) -> DbResult<()>;
242 async fn change_pwd(&self, user_name: &UserName, new_pwd: &str) -> DbResult<()>;
243 async fn change_read_only_state(&self, user_name: &UserName, state: bool) -> DbResult<()>;
244 async fn change_admin_state(&self, user_name: &UserName, state: bool) -> DbResult<()>;
245 async fn crate_version_exists(&self, crate_id: CrateId, version: &Version) -> DbResult<bool>;
246 async fn get_max_version_from_id(&self, crate_id: CrateId) -> DbResult<Version>;
247 async fn get_max_version_from_name(&self, crate_name: &CanonicalName) -> DbResult<Version>;
248 async fn add_auth_token(&self, name: &str, token: &PlainToken, user: &UserName)
249 -> DbResult<()>;
250 async fn get_user_from_token(&self, token: &PlainToken) -> DbResult<User>;
251 async fn get_auth_token_name(&self, token: &PlainToken) -> DbResult<Option<String>>;
253 async fn get_user(&self, name: &UserName) -> DbResult<User>;
254 async fn get_auth_tokens(&self, user_name: &UserName) -> DbResult<Vec<AuthToken>>;
255 async fn delete_auth_token(&self, user_name: &UserName, id: AuthTokenId) -> DbResult<()>;
258 async fn delete_owners(
263 &self,
264 crate_name: &CanonicalName,
265 owners: &[UserName],
266 allow_ownerless: bool,
267 ) -> DbResult<()>;
268 async fn delete_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<()>;
269 async fn add_user(&self, name: &UserName, pwd: &str, flags: UserFlags) -> DbResult<()>;
270 async fn get_users(&self) -> DbResult<Vec<User>>;
271 async fn add_group(&self, name: &GroupName) -> DbResult<()>;
272 async fn get_groups(&self) -> DbResult<Vec<Group>>;
273 async fn delete_group(&self, name: &GroupName) -> DbResult<()>;
274 async fn add_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<()>;
275 async fn delete_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<()>;
276 async fn get_group_users(&self, group_name: &GroupName) -> DbResult<Vec<User>>;
277 async fn is_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<bool>;
278 async fn add_crate_group(&self, crate_name: &CanonicalName, group: &GroupName) -> DbResult<()>;
279 async fn delete_crate_group(
280 &self,
281 crate_name: &CanonicalName,
282 group: &GroupName,
283 ) -> DbResult<()>;
284 async fn get_crate_groups(&self, crate_name: &CanonicalName) -> DbResult<Vec<Group>>;
285 async fn is_crate_group(&self, crate_name: &CanonicalName, group: &GroupName)
286 -> DbResult<bool>;
287 async fn is_crate_group_user(
288 &self,
289 crate_name: &CanonicalName,
290 user: &UserName,
291 ) -> DbResult<bool>;
292 async fn get_total_unique_crates(&self) -> DbResult<u64>;
293 async fn get_total_crate_versions(&self) -> DbResult<u64>;
294 async fn get_total_downloads(&self) -> DbResult<u64>;
295 async fn get_top_crates_downloads(
296 &self,
297 top: u64,
298 visibility: &CrateVisibility,
299 ) -> DbResult<Vec<(String, u64)>>;
300 async fn get_total_unique_cached_crates(&self) -> DbResult<u64>;
301 async fn get_total_cached_crate_versions(&self) -> DbResult<u64>;
302 async fn get_total_cached_downloads(&self) -> DbResult<u64>;
303 async fn add_doc_queue(
304 &self,
305 krate: &OriginalName,
306 version: &Version,
307 path: &Path,
308 ) -> DbResult<()>;
309 async fn delete_doc_queue(&self, id: i64) -> DbResult<()>;
310 async fn get_doc_queue(&self) -> DbResult<Vec<DocQueueEntry>>;
311 async fn delete_crate(&self, krate: &CanonicalName, version: &Version) -> DbResult<()>;
312 async fn get_crate_meta_list(&self, crate_name: &CanonicalName) -> DbResult<Vec<CrateMeta>>;
313 async fn search_in_crate_name_and_description(
314 &self,
315 contains: &str,
316 limit: u64,
317 offset: u64,
318 cache: bool,
319 visibility: &CrateVisibility,
320 ) -> DbResult<Vec<CrateOverview>>;
321 async fn count_by_crate_name_and_description(
322 &self,
323 contains: &str,
324 cache: bool,
325 visibility: &CrateVisibility,
326 ) -> DbResult<u64>;
327 async fn get_crate_overview_list(
328 &self,
329 limit: u64,
330 offset: u64,
331 cache: bool,
332 visibility: &CrateVisibility,
333 sort: CrateSort,
334 tags: &CrateTagFilter,
335 ) -> DbResult<Vec<CrateOverview>>;
336 async fn count_crate_overview_list(
337 &self,
338 cache: bool,
339 visibility: &CrateVisibility,
340 tags: &CrateTagFilter,
341 ) -> DbResult<u64>;
342 async fn get_crate_data(&self, crate_name: &CanonicalName) -> DbResult<CrateData>;
343 async fn get_crate_dependents(&self, crate_name: &CanonicalName) -> DbResult<CrateDependents>;
347 async fn add_empty_crate(&self, name: &str, created: &DateTime<Utc>) -> DbResult<CrateId>;
348 async fn add_crate(
352 &self,
353 pub_metadata: &PublishMetadata,
354 cksum: &str,
355 size: i64,
356 created: &DateTime<Utc>,
357 owner: &UserName,
358 token_name: Option<String>,
359 ) -> DbResult<CrateId>;
360 async fn update_docs_link(
361 &self,
362 crate_name: &CanonicalName,
363 version: &Version,
364 docs_link: &str,
365 ) -> DbResult<()>;
366 async fn get_prefetch_data(&self, crate_name: &OriginalName) -> DbResult<Prefetch>;
367 async fn is_cratesio_cache_up_to_date(
368 &self,
369 crate_name: &OriginalName,
370 if_none_match: Option<String>,
371 if_modified_since: Option<String>,
372 ) -> DbResult<PrefetchState>;
373 async fn add_cratesio_prefetch_data(
374 &self,
375 crate_name: &OriginalName,
376 etag: &str,
377 last_modified: &str,
378 description: Option<String>,
379 indices: &[IndexMetadata],
380 licenses: &HashMap<String, String>,
381 ) -> DbResult<Prefetch>;
382 async fn get_cratesio_index_update_list(&self) -> DbResult<Vec<CratesioPrefetchMsg>>;
383 async fn get_cratesio_version_meta(
386 &self,
387 crate_name: &CanonicalName,
388 version: &Version,
389 ) -> DbResult<Option<CratesioVersionMeta>>;
390 async fn get_crate_license(
393 &self,
394 crate_name: &CanonicalName,
395 version: &Version,
396 ) -> DbResult<Option<String>>;
397 async fn unyank_crate(&self, crate_name: &CanonicalName, version: &Version) -> DbResult<()>;
398 async fn yank_crate(&self, crate_name: &CanonicalName, version: &Version) -> DbResult<()>;
399 async fn register_webhook(&self, webhook: Webhook) -> DbResult<String>;
400 async fn delete_webhook(&self, id: &str) -> DbResult<()>;
401 async fn get_webhook(&self, id: &str) -> DbResult<Webhook>;
402 async fn get_all_webhooks(&self) -> DbResult<Vec<Webhook>>;
403 async fn add_webhook_queue(
407 &self,
408 event: WebhookEvent,
409 payload: serde_json::Value,
410 ) -> DbResult<()>;
411 async fn get_pending_webhook_queue_entries(
413 &self,
414 timestamp: DateTime<Utc>,
415 ) -> DbResult<Vec<WebhookQueue>>;
416 async fn update_webhook_queue(
417 &self,
418 id: &str,
419 last_attempt: DateTime<Utc>,
420 next_attempt: DateTime<Utc>,
421 ) -> DbResult<()>;
422 async fn delete_webhook_queue(&self, id: &str) -> DbResult<()>;
423
424 async fn get_user_by_oauth2_identity(
427 &self,
428 issuer: &str,
429 subject: &str,
430 ) -> DbResult<Option<User>>;
431
432 async fn has_oauth2_admin(&self) -> DbResult<bool>;
438
439 async fn create_oauth2_user(
441 &self,
442 username: &UserName,
443 issuer: &str,
444 subject: &str,
445 email: Option<String>,
446 flags: UserFlags,
447 ) -> DbResult<User>;
448
449 async fn store_oauth2_state(
452 &self,
453 state: &str,
454 pkce_verifier: &str,
455 nonce: &str,
456 ) -> DbResult<()>;
457
458 async fn get_and_delete_oauth2_state(&self, state: &str) -> DbResult<Option<OAuth2StateData>>;
460
461 async fn cleanup_expired_oauth2_states(&self) -> DbResult<u64>;
463
464 async fn is_username_available(&self, username: &UserName) -> DbResult<bool>;
466
467 async fn add_toolchain(
470 &self,
471 name: &str,
472 version: &str,
473 date: &str,
474 channel: Option<String>,
475 ) -> DbResult<i64>;
476
477 async fn add_toolchain_target(
479 &self,
480 toolchain_id: i64,
481 target: &str,
482 storage_path: &str,
483 hash: &str,
484 size: i64,
485 ) -> DbResult<i64>;
486
487 async fn add_toolchain_component(
489 &self,
490 target_id: i64,
491 name: &str,
492 storage_path: &str,
493 hash: &str,
494 size: i64,
495 ) -> DbResult<()>;
496
497 async fn is_toolchain_component_stored_at(&self, storage_path: &str) -> DbResult<bool>;
499
500 async fn set_target_status(
502 &self,
503 target_id: i64,
504 status: ToolchainTargetStatus,
505 ) -> DbResult<()>;
506
507 async fn fail_processing_toolchain_targets(&self) -> DbResult<u64>;
510
511 async fn get_toolchain_by_channel(
513 &self,
514 channel: &str,
515 ) -> DbResult<Option<ToolchainWithTargets>>;
516
517 async fn get_toolchain_by_version(
519 &self,
520 name: &str,
521 version: &str,
522 ) -> DbResult<Option<ToolchainWithTargets>>;
523
524 async fn list_toolchains(&self) -> DbResult<Vec<ToolchainWithTargets>>;
526
527 async fn delete_toolchain(&self, name: &str, version: &str) -> DbResult<()>;
529
530 async fn delete_toolchain_target(
532 &self,
533 name: &str,
534 version: &str,
535 target: &str,
536 ) -> DbResult<()>;
537
538 async fn set_channel(&self, channel: &str, name: &str, version: &str) -> DbResult<()>;
540
541 async fn get_channels(&self) -> DbResult<Vec<ChannelInfo>>;
543
544 async fn get_crate_original_name(
547 &self,
548 crate_name: &CanonicalName,
549 ) -> DbResult<Option<OriginalName>>;
550
551 async fn get_original_name(
553 &self,
554 crate_name: &CanonicalName,
555 version: &Version,
556 ) -> DbResult<Option<OriginalName>>;
557}
558
559#[cfg(feature = "mock")]
560pub mod mock {
561 pub use super::MockDbProvider as MockDb;
562}