use std::collections::HashMap;
use std::path::Path;
use chrono::{DateTime, Utc};
use crate_meta::CrateMeta;
use kellnr_common::account_name::{GroupName, UserName};
use kellnr_common::canonical_name::CanonicalName;
use kellnr_common::crate_data::CrateData;
use kellnr_common::crate_dependents::CrateDependents;
use kellnr_common::crate_overview::CrateOverview;
use kellnr_common::cratesio_prefetch_msg::CratesioPrefetchMsg;
use kellnr_common::index_metadata::IndexMetadata;
use kellnr_common::original_name::OriginalName;
use kellnr_common::plain_token::PlainToken;
use kellnr_common::prefetch::Prefetch;
use kellnr_common::publish_metadata::PublishMetadata;
use kellnr_common::version::Version;
use kellnr_common::webhook::{Webhook, WebhookEvent, WebhookQueue};
use sea_orm::prelude::async_trait::async_trait;
use serde::{Deserialize, Serialize};
use crate::error::DbError;
use crate::{
AuthToken, AuthTokenId, CrateId, DocQueueEntry, Group, ToolchainTargetStatus, User, UserFlags,
crate_meta,
};
pub type DbResult<T> = Result<T, DbError>;
#[derive(Debug, PartialEq, Eq)]
pub enum PrefetchState {
UpToDate {
etag: String,
last_modified: String,
},
NeedsUpdate(Prefetch),
NotFound,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CratesioVersionMeta {
pub cksum: String,
pub license: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CrateVisibility {
All,
User(UserName),
Unrestricted,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
#[serde(rename_all = "lowercase")]
pub enum CrateSort {
#[default]
Name,
Updated,
Downloads,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CrateTagFilter {
pub keyword: Option<String>,
pub category: Option<String>,
}
impl CrateTagFilter {
pub fn is_empty(&self) -> bool {
self.keyword.is_none() && self.category.is_none()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SessionInfo {
pub name: UserName,
pub is_admin: bool,
pub is_read_only: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OAuth2StateData {
pub state: String,
pub pkce_verifier: String,
pub nonce: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
pub struct ToolchainComponentInfo {
pub name: String,
pub storage_path: String,
pub hash: String,
pub size: i64,
}
impl From<kellnr_entity::toolchain_component::Model> for ToolchainComponentInfo {
fn from(c: kellnr_entity::toolchain_component::Model) -> Self {
Self {
name: c.name,
storage_path: c.storage_path,
hash: c.hash,
size: c.size,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
pub struct ToolchainTargetInfo {
pub id: i64,
pub target: String,
pub storage_path: String,
pub hash: String,
pub size: i64,
pub status: ToolchainTargetStatus,
pub components: Vec<ToolchainComponentInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
pub struct ToolchainWithTargets {
pub id: i64,
pub name: String,
pub version: String,
pub date: String,
pub channel: Option<String>,
pub created: String,
pub targets: Vec<ToolchainTargetInfo>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, utoipa::ToSchema)]
pub struct ChannelInfo {
pub name: String,
pub version: String,
pub date: String,
}
#[cfg_attr(feature = "mock", mockall::automock)]
#[async_trait]
pub trait DbProvider: Send + Sync {
async fn get_last_updated_crate(
&self,
visibility: &CrateVisibility,
) -> DbResult<Option<(OriginalName, Version)>>;
async fn authenticate_user(&self, name: &UserName, pwd: &str) -> DbResult<User>;
async fn increase_download_counter(
&self,
crate_name: &CanonicalName,
crate_version: &Version,
) -> DbResult<()>;
async fn increase_cached_download_counter(
&self,
crate_name: &CanonicalName,
crate_version: &Version,
) -> DbResult<()>;
async fn increase_download_counter_by(
&self,
crate_name: &CanonicalName,
crate_version: &Version,
count: u64,
) -> DbResult<()>;
async fn increase_cached_download_counter_by(
&self,
crate_name: &CanonicalName,
crate_version: &Version,
count: u64,
) -> DbResult<()>;
async fn validate_session(&self, session_token: &PlainToken) -> DbResult<SessionInfo>;
async fn delete_expired_sessions(&self) -> DbResult<u64>;
async fn add_session_token(&self, name: &UserName, session_token: &PlainToken) -> DbResult<()>;
async fn delete_user_sessions(&self, user_name: &UserName) -> DbResult<u64>;
async fn delete_other_user_sessions(
&self,
user_name: &UserName,
keep_session_token: &PlainToken,
) -> DbResult<u64>;
async fn add_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<()>;
async fn add_owner(&self, crate_name: &CanonicalName, owner: &UserName) -> DbResult<()>;
async fn is_download_restricted(&self, crate_name: &CanonicalName) -> DbResult<bool>;
async fn change_download_restricted(
&self,
crate_name: &CanonicalName,
restricted: bool,
) -> DbResult<()>;
async fn is_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<bool>;
async fn is_owner(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<bool>;
async fn get_crate_id(&self, crate_name: &CanonicalName) -> DbResult<Option<CrateId>>;
async fn get_crate_owners(&self, crate_name: &CanonicalName) -> DbResult<Vec<User>>;
async fn get_crate_users(&self, crate_name: &CanonicalName) -> DbResult<Vec<User>>;
async fn get_crate_versions(&self, crate_name: &CanonicalName) -> DbResult<Vec<Version>>;
async fn delete_session_token(&self, session_token: &PlainToken) -> DbResult<()>;
async fn delete_user(&self, user_name: &UserName) -> DbResult<()>;
async fn change_pwd(&self, user_name: &UserName, new_pwd: &str) -> DbResult<()>;
async fn change_read_only_state(&self, user_name: &UserName, state: bool) -> DbResult<()>;
async fn change_admin_state(&self, user_name: &UserName, state: bool) -> DbResult<()>;
async fn crate_version_exists(&self, crate_id: CrateId, version: &Version) -> DbResult<bool>;
async fn get_max_version_from_id(&self, crate_id: CrateId) -> DbResult<Version>;
async fn get_max_version_from_name(&self, crate_name: &CanonicalName) -> DbResult<Version>;
async fn add_auth_token(&self, name: &str, token: &PlainToken, user: &UserName)
-> DbResult<()>;
async fn get_user_from_token(&self, token: &PlainToken) -> DbResult<User>;
async fn get_auth_token_name(&self, token: &PlainToken) -> DbResult<Option<String>>;
async fn get_user(&self, name: &UserName) -> DbResult<User>;
async fn get_auth_tokens(&self, user_name: &UserName) -> DbResult<Vec<AuthToken>>;
async fn delete_auth_token(&self, user_name: &UserName, id: AuthTokenId) -> DbResult<()>;
async fn delete_owners(
&self,
crate_name: &CanonicalName,
owners: &[UserName],
allow_ownerless: bool,
) -> DbResult<()>;
async fn delete_crate_user(&self, crate_name: &CanonicalName, user: &UserName) -> DbResult<()>;
async fn add_user(&self, name: &UserName, pwd: &str, flags: UserFlags) -> DbResult<()>;
async fn get_users(&self) -> DbResult<Vec<User>>;
async fn add_group(&self, name: &GroupName) -> DbResult<()>;
async fn get_groups(&self) -> DbResult<Vec<Group>>;
async fn delete_group(&self, name: &GroupName) -> DbResult<()>;
async fn add_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<()>;
async fn delete_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<()>;
async fn get_group_users(&self, group_name: &GroupName) -> DbResult<Vec<User>>;
async fn is_group_user(&self, group_name: &GroupName, user: &UserName) -> DbResult<bool>;
async fn add_crate_group(&self, crate_name: &CanonicalName, group: &GroupName) -> DbResult<()>;
async fn delete_crate_group(
&self,
crate_name: &CanonicalName,
group: &GroupName,
) -> DbResult<()>;
async fn get_crate_groups(&self, crate_name: &CanonicalName) -> DbResult<Vec<Group>>;
async fn is_crate_group(&self, crate_name: &CanonicalName, group: &GroupName)
-> DbResult<bool>;
async fn is_crate_group_user(
&self,
crate_name: &CanonicalName,
user: &UserName,
) -> DbResult<bool>;
async fn get_total_unique_crates(&self) -> DbResult<u64>;
async fn get_total_crate_versions(&self) -> DbResult<u64>;
async fn get_total_downloads(&self) -> DbResult<u64>;
async fn get_top_crates_downloads(
&self,
top: u64,
visibility: &CrateVisibility,
) -> DbResult<Vec<(String, u64)>>;
async fn get_total_unique_cached_crates(&self) -> DbResult<u64>;
async fn get_total_cached_crate_versions(&self) -> DbResult<u64>;
async fn get_total_cached_downloads(&self) -> DbResult<u64>;
async fn add_doc_queue(
&self,
krate: &OriginalName,
version: &Version,
path: &Path,
) -> DbResult<()>;
async fn delete_doc_queue(&self, id: i64) -> DbResult<()>;
async fn get_doc_queue(&self) -> DbResult<Vec<DocQueueEntry>>;
async fn delete_crate(&self, krate: &CanonicalName, version: &Version) -> DbResult<()>;
async fn get_crate_meta_list(&self, crate_name: &CanonicalName) -> DbResult<Vec<CrateMeta>>;
async fn search_in_crate_name_and_description(
&self,
contains: &str,
limit: u64,
offset: u64,
cache: bool,
visibility: &CrateVisibility,
) -> DbResult<Vec<CrateOverview>>;
async fn count_by_crate_name_and_description(
&self,
contains: &str,
cache: bool,
visibility: &CrateVisibility,
) -> DbResult<u64>;
async fn get_crate_overview_list(
&self,
limit: u64,
offset: u64,
cache: bool,
visibility: &CrateVisibility,
sort: CrateSort,
tags: &CrateTagFilter,
) -> DbResult<Vec<CrateOverview>>;
async fn count_crate_overview_list(
&self,
cache: bool,
visibility: &CrateVisibility,
tags: &CrateTagFilter,
) -> DbResult<u64>;
async fn get_crate_data(&self, crate_name: &CanonicalName) -> DbResult<CrateData>;
async fn get_crate_dependents(&self, crate_name: &CanonicalName) -> DbResult<CrateDependents>;
async fn add_empty_crate(&self, name: &str, created: &DateTime<Utc>) -> DbResult<CrateId>;
async fn add_crate(
&self,
pub_metadata: &PublishMetadata,
cksum: &str,
size: i64,
created: &DateTime<Utc>,
owner: &UserName,
token_name: Option<String>,
) -> DbResult<CrateId>;
async fn update_docs_link(
&self,
crate_name: &CanonicalName,
version: &Version,
docs_link: &str,
) -> DbResult<()>;
async fn get_prefetch_data(&self, crate_name: &OriginalName) -> DbResult<Prefetch>;
async fn is_cratesio_cache_up_to_date(
&self,
crate_name: &OriginalName,
if_none_match: Option<String>,
if_modified_since: Option<String>,
) -> DbResult<PrefetchState>;
async fn add_cratesio_prefetch_data(
&self,
crate_name: &OriginalName,
etag: &str,
last_modified: &str,
description: Option<String>,
indices: &[IndexMetadata],
licenses: &HashMap<String, String>,
) -> DbResult<Prefetch>;
async fn get_cratesio_index_update_list(&self) -> DbResult<Vec<CratesioPrefetchMsg>>;
async fn get_cratesio_version_meta(
&self,
crate_name: &CanonicalName,
version: &Version,
) -> DbResult<Option<CratesioVersionMeta>>;
async fn get_crate_license(
&self,
crate_name: &CanonicalName,
version: &Version,
) -> DbResult<Option<String>>;
async fn unyank_crate(&self, crate_name: &CanonicalName, version: &Version) -> DbResult<()>;
async fn yank_crate(&self, crate_name: &CanonicalName, version: &Version) -> DbResult<()>;
async fn register_webhook(&self, webhook: Webhook) -> DbResult<String>;
async fn delete_webhook(&self, id: &str) -> DbResult<()>;
async fn get_webhook(&self, id: &str) -> DbResult<Webhook>;
async fn get_all_webhooks(&self) -> DbResult<Vec<Webhook>>;
async fn add_webhook_queue(
&self,
event: WebhookEvent,
payload: serde_json::Value,
) -> DbResult<()>;
async fn get_pending_webhook_queue_entries(
&self,
timestamp: DateTime<Utc>,
) -> DbResult<Vec<WebhookQueue>>;
async fn update_webhook_queue(
&self,
id: &str,
last_attempt: DateTime<Utc>,
next_attempt: DateTime<Utc>,
) -> DbResult<()>;
async fn delete_webhook_queue(&self, id: &str) -> DbResult<()>;
async fn get_user_by_oauth2_identity(
&self,
issuer: &str,
subject: &str,
) -> DbResult<Option<User>>;
async fn has_oauth2_admin(&self) -> DbResult<bool>;
async fn create_oauth2_user(
&self,
username: &UserName,
issuer: &str,
subject: &str,
email: Option<String>,
flags: UserFlags,
) -> DbResult<User>;
async fn store_oauth2_state(
&self,
state: &str,
pkce_verifier: &str,
nonce: &str,
) -> DbResult<()>;
async fn get_and_delete_oauth2_state(&self, state: &str) -> DbResult<Option<OAuth2StateData>>;
async fn cleanup_expired_oauth2_states(&self) -> DbResult<u64>;
async fn is_username_available(&self, username: &UserName) -> DbResult<bool>;
async fn add_toolchain(
&self,
name: &str,
version: &str,
date: &str,
channel: Option<String>,
) -> DbResult<i64>;
async fn add_toolchain_target(
&self,
toolchain_id: i64,
target: &str,
storage_path: &str,
hash: &str,
size: i64,
) -> DbResult<i64>;
async fn add_toolchain_component(
&self,
target_id: i64,
name: &str,
storage_path: &str,
hash: &str,
size: i64,
) -> DbResult<()>;
async fn is_toolchain_component_stored_at(&self, storage_path: &str) -> DbResult<bool>;
async fn set_target_status(
&self,
target_id: i64,
status: ToolchainTargetStatus,
) -> DbResult<()>;
async fn fail_processing_toolchain_targets(&self) -> DbResult<u64>;
async fn get_toolchain_by_channel(
&self,
channel: &str,
) -> DbResult<Option<ToolchainWithTargets>>;
async fn get_toolchain_by_version(
&self,
name: &str,
version: &str,
) -> DbResult<Option<ToolchainWithTargets>>;
async fn list_toolchains(&self) -> DbResult<Vec<ToolchainWithTargets>>;
async fn delete_toolchain(&self, name: &str, version: &str) -> DbResult<()>;
async fn delete_toolchain_target(
&self,
name: &str,
version: &str,
target: &str,
) -> DbResult<()>;
async fn set_channel(&self, channel: &str, name: &str, version: &str) -> DbResult<()>;
async fn get_channels(&self) -> DbResult<Vec<ChannelInfo>>;
async fn get_crate_original_name(
&self,
crate_name: &CanonicalName,
) -> DbResult<Option<OriginalName>>;
async fn get_original_name(
&self,
crate_name: &CanonicalName,
version: &Version,
) -> DbResult<Option<OriginalName>>;
}
#[cfg(feature = "mock")]
pub mod mock {
pub use super::MockDbProvider as MockDb;
}