2023-01-11 19:33:56 +08:00
use std ::convert ::Infallible ;
use std ::fmt ::Display ;
2022-10-21 00:00:07 +08:00
use std ::hash ::Hash ;
2023-01-11 21:31:34 +08:00
use deserr ::{ DeserializeError , DeserializeFromValue , MergeWithError , ValuePointerRef } ;
2022-10-18 00:57:23 +08:00
use enum_iterator ::Sequence ;
2022-10-12 22:10:28 +08:00
use serde ::{ Deserialize , Serialize } ;
use time ::format_description ::well_known ::Rfc3339 ;
use time ::macros ::{ format_description , time } ;
use time ::{ Date , OffsetDateTime , PrimitiveDateTime } ;
use uuid ::Uuid ;
2023-01-11 19:33:56 +08:00
use crate ::error ::deserr_codes ::* ;
use crate ::error ::{ unwrap_any , Code , DeserrError , ErrorCode , TakeErrorMessage } ;
2023-01-25 21:42:03 +08:00
use crate ::index_uid_pattern ::{ IndexUidPattern , IndexUidPatternFormatError } ;
2022-10-21 00:00:07 +08:00
2022-10-12 22:10:28 +08:00
pub type KeyId = Uuid ;
2023-01-25 21:42:03 +08:00
impl < C : Default + ErrorCode > MergeWithError < IndexUidPatternFormatError > for DeserrError < C > {
2023-01-11 19:33:56 +08:00
fn merge (
_self_ : Option < Self > ,
2023-01-25 21:42:03 +08:00
other : IndexUidPatternFormatError ,
2023-01-11 19:33:56 +08:00
merge_location : deserr ::ValuePointerRef ,
) -> std ::result ::Result < Self , Self > {
DeserrError ::error ::< Infallible > (
None ,
deserr ::ErrorKind ::Unexpected { msg : other . to_string ( ) } ,
merge_location ,
)
}
}
2023-01-11 21:31:34 +08:00
fn parse_uuid_from_str ( s : & str ) -> Result < Uuid , TakeErrorMessage < uuid ::Error > > {
Uuid ::parse_str ( s ) . map_err ( TakeErrorMessage )
}
2023-01-11 19:33:56 +08:00
#[ derive(Debug, DeserializeFromValue) ]
#[ deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields) ]
pub struct CreateApiKey {
#[ deserr(error = DeserrError<InvalidApiKeyDescription>) ]
pub description : Option < String > ,
#[ deserr(error = DeserrError<InvalidApiKeyName>) ]
pub name : Option < String > ,
2023-01-11 21:31:34 +08:00
#[ deserr(default = Uuid::new_v4(), error = DeserrError<InvalidApiKeyUid>, from(&String) = parse_uuid_from_str -> TakeErrorMessage<uuid::Error>) ]
2023-01-11 19:33:56 +08:00
pub uid : KeyId ,
#[ deserr(error = DeserrError<InvalidApiKeyActions>) ]
pub actions : Vec < Action > ,
#[ deserr(error = DeserrError<InvalidApiKeyIndexes>) ]
2023-01-26 00:22:32 +08:00
pub indexes : Vec < IndexUidPattern > ,
2023-01-11 19:33:56 +08:00
#[ deserr(error = DeserrError<InvalidApiKeyExpiresAt>, default = None, from(&String) = parse_expiration_date -> TakeErrorMessage<ParseOffsetDateTimeError>) ]
pub expires_at : Option < OffsetDateTime > ,
}
2023-01-25 21:42:03 +08:00
2023-01-11 19:33:56 +08:00
impl CreateApiKey {
pub fn to_key ( self ) -> Key {
let CreateApiKey { description , name , uid , actions , indexes , expires_at } = self ;
let now = OffsetDateTime ::now_utc ( ) ;
Key {
description ,
name ,
uid ,
actions ,
indexes ,
expires_at ,
created_at : now ,
updated_at : now ,
}
}
}
fn deny_immutable_fields_api_key (
field : & str ,
accepted : & [ & str ] ,
location : ValuePointerRef ,
) -> DeserrError {
let mut error = unwrap_any ( DeserrError ::< BadRequest > ::error ::< Infallible > (
None ,
deserr ::ErrorKind ::UnknownKey { key : field , accepted } ,
location ,
) ) ;
error . code = match field {
2023-01-12 16:35:56 +08:00
" uid " = > Code ::ImmutableApiKeyUid ,
" actions " = > Code ::ImmutableApiKeyActions ,
" indexes " = > Code ::ImmutableApiKeyIndexes ,
" expiresAt " = > Code ::ImmutableApiKeyExpiresAt ,
" createdAt " = > Code ::ImmutableApiKeyCreatedAt ,
" updatedAt " = > Code ::ImmutableApiKeyUpdatedAt ,
2023-01-11 19:33:56 +08:00
_ = > Code ::BadRequest ,
} ;
error
}
#[ derive(Debug, DeserializeFromValue) ]
#[ deserr(error = DeserrError, rename_all = camelCase, deny_unknown_fields = deny_immutable_fields_api_key) ]
pub struct PatchApiKey {
#[ deserr(error = DeserrError<InvalidApiKeyDescription>) ]
pub description : Option < String > ,
#[ deserr(error = DeserrError<InvalidApiKeyName>) ]
pub name : Option < String > ,
}
2022-10-16 07:39:01 +08:00
#[ derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize) ]
2022-10-12 22:10:28 +08:00
pub struct Key {
#[ serde(skip_serializing_if = " Option::is_none " ) ]
pub description : Option < String > ,
#[ serde(skip_serializing_if = " Option::is_none " ) ]
pub name : Option < String > ,
pub uid : KeyId ,
pub actions : Vec < Action > ,
2023-01-26 00:22:32 +08:00
pub indexes : Vec < IndexUidPattern > ,
2022-10-12 22:10:28 +08:00
#[ serde(with = " time::serde::rfc3339::option " ) ]
pub expires_at : Option < OffsetDateTime > ,
#[ serde(with = " time::serde::rfc3339 " ) ]
pub created_at : OffsetDateTime ,
#[ serde(with = " time::serde::rfc3339 " ) ]
pub updated_at : OffsetDateTime ,
}
impl Key {
pub fn default_admin ( ) -> Self {
let now = OffsetDateTime ::now_utc ( ) ;
let uid = Uuid ::new_v4 ( ) ;
Self {
name : Some ( " Default Admin API Key " . to_string ( ) ) ,
description : Some ( " Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend " . to_string ( ) ) ,
uid ,
actions : vec ! [ Action ::All ] ,
2023-01-26 00:22:32 +08:00
indexes : vec ! [ IndexUidPattern ::all ( ) ] ,
2022-10-12 22:10:28 +08:00
expires_at : None ,
created_at : now ,
updated_at : now ,
}
}
pub fn default_search ( ) -> Self {
let now = OffsetDateTime ::now_utc ( ) ;
let uid = Uuid ::new_v4 ( ) ;
Self {
name : Some ( " Default Search API Key " . to_string ( ) ) ,
description : Some ( " Use it to search from the frontend " . to_string ( ) ) ,
uid ,
actions : vec ! [ Action ::Search ] ,
2023-01-26 00:22:32 +08:00
indexes : vec ! [ IndexUidPattern ::all ( ) ] ,
2022-10-12 22:10:28 +08:00
expires_at : None ,
created_at : now ,
updated_at : now ,
}
}
}
2023-01-11 19:33:56 +08:00
#[ derive(Debug) ]
pub struct ParseOffsetDateTimeError ( String ) ;
impl Display for ParseOffsetDateTimeError {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
writeln! ( f , " `{original}` is not a valid date. It should follow the RFC 3339 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'. " , original = self . 0 )
}
}
impl std ::error ::Error for ParseOffsetDateTimeError { }
fn parse_expiration_date (
string : & str ,
) -> std ::result ::Result < Option < OffsetDateTime > , TakeErrorMessage < ParseOffsetDateTimeError > > {
let datetime = if let Ok ( datetime ) = OffsetDateTime ::parse ( string , & Rfc3339 ) {
datetime
} else if let Ok ( primitive_datetime ) = PrimitiveDateTime ::parse (
string ,
format_description! (
" [year repr:full base:calendar]-[month repr:numerical]-[day]T[hour]:[minute]:[second] "
) ,
) {
primitive_datetime . assume_utc ( )
} else if let Ok ( primitive_datetime ) = PrimitiveDateTime ::parse (
string ,
format_description! (
" [year repr:full base:calendar]-[month repr:numerical]-[day] [hour]:[minute]:[second] "
) ,
) {
primitive_datetime . assume_utc ( )
} else if let Ok ( date ) = Date ::parse (
string ,
format_description! ( " [year repr:full base:calendar]-[month repr:numerical]-[day] " ) ,
) {
PrimitiveDateTime ::new ( date , time! ( 00 :00 ) ) . assume_utc ( )
} else {
return Err ( TakeErrorMessage ( ParseOffsetDateTimeError ( string . to_owned ( ) ) ) ) ;
} ;
if datetime > OffsetDateTime ::now_utc ( ) {
Ok ( Some ( datetime ) )
} else {
Err ( TakeErrorMessage ( ParseOffsetDateTimeError ( string . to_owned ( ) ) ) )
2022-10-12 22:10:28 +08:00
}
}
2023-01-11 19:33:56 +08:00
#[ derive(
Copy , Clone , Serialize , Deserialize , Debug , Eq , PartialEq , Hash , Sequence , DeserializeFromValue ,
) ]
2022-10-12 22:10:28 +08:00
#[ repr(u8) ]
pub enum Action {
#[ serde(rename = " * " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " * " ) ]
2022-10-12 22:10:28 +08:00
All = 0 ,
#[ serde(rename = " search " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " search " ) ]
2022-10-12 22:10:28 +08:00
Search ,
#[ serde(rename = " documents.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " documents.* " ) ]
2022-10-12 22:10:28 +08:00
DocumentsAll ,
#[ serde(rename = " documents.add " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " documents.add " ) ]
2022-10-12 22:10:28 +08:00
DocumentsAdd ,
#[ serde(rename = " documents.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " documents.get " ) ]
2022-10-12 22:10:28 +08:00
DocumentsGet ,
#[ serde(rename = " documents.delete " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " documents.delete " ) ]
2022-10-12 22:10:28 +08:00
DocumentsDelete ,
#[ serde(rename = " indexes.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.* " ) ]
2022-10-12 22:10:28 +08:00
IndexesAll ,
#[ serde(rename = " indexes.create " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.create " ) ]
2022-10-12 22:10:28 +08:00
IndexesAdd ,
#[ serde(rename = " indexes.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.get " ) ]
2022-10-12 22:10:28 +08:00
IndexesGet ,
#[ serde(rename = " indexes.update " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.update " ) ]
2022-10-12 22:10:28 +08:00
IndexesUpdate ,
#[ serde(rename = " indexes.delete " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.delete " ) ]
2022-10-12 22:10:28 +08:00
IndexesDelete ,
2022-10-17 22:30:18 +08:00
#[ serde(rename = " indexes.swap " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " indexes.swap " ) ]
2022-10-17 22:30:18 +08:00
IndexesSwap ,
2022-10-12 22:10:28 +08:00
#[ serde(rename = " tasks.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " tasks.* " ) ]
2022-10-12 22:10:28 +08:00
TasksAll ,
2022-10-18 20:48:40 +08:00
#[ serde(rename = " tasks.cancel " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " tasks.cancel " ) ]
2022-10-18 20:48:40 +08:00
TasksCancel ,
2022-10-15 17:03:24 +08:00
#[ serde(rename = " tasks.delete " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " tasks.delete " ) ]
2022-10-13 17:09:00 +08:00
TasksDelete ,
2022-10-12 22:10:28 +08:00
#[ serde(rename = " tasks.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " tasks.get " ) ]
2022-10-12 22:10:28 +08:00
TasksGet ,
#[ serde(rename = " settings.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " settings.* " ) ]
2022-10-12 22:10:28 +08:00
SettingsAll ,
#[ serde(rename = " settings.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " settings.get " ) ]
2022-10-12 22:10:28 +08:00
SettingsGet ,
#[ serde(rename = " settings.update " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " settings.update " ) ]
2022-10-12 22:10:28 +08:00
SettingsUpdate ,
#[ serde(rename = " stats.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " stats.* " ) ]
2022-10-12 22:10:28 +08:00
StatsAll ,
#[ serde(rename = " stats.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " stats.get " ) ]
2022-10-12 22:10:28 +08:00
StatsGet ,
#[ serde(rename = " metrics.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " metrics.* " ) ]
2022-10-12 22:10:28 +08:00
MetricsAll ,
#[ serde(rename = " metrics.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " metrics.get " ) ]
2022-10-12 22:10:28 +08:00
MetricsGet ,
#[ serde(rename = " dumps.* " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " dumps.* " ) ]
2022-10-12 22:10:28 +08:00
DumpsAll ,
#[ serde(rename = " dumps.create " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " dumps.create " ) ]
2022-10-12 22:10:28 +08:00
DumpsCreate ,
#[ serde(rename = " version " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " version " ) ]
2022-10-12 22:10:28 +08:00
Version ,
#[ serde(rename = " keys.create " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " keys.create " ) ]
2022-10-12 22:10:28 +08:00
KeysAdd ,
#[ serde(rename = " keys.get " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " keys.get " ) ]
2022-10-12 22:10:28 +08:00
KeysGet ,
#[ serde(rename = " keys.update " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " keys.update " ) ]
2022-10-12 22:10:28 +08:00
KeysUpdate ,
#[ serde(rename = " keys.delete " ) ]
2023-01-11 19:33:56 +08:00
#[ deserr(rename = " keys.delete " ) ]
2022-10-12 22:10:28 +08:00
KeysDelete ,
}
impl Action {
pub const fn from_repr ( repr : u8 ) -> Option < Self > {
use actions ::* ;
match repr {
ALL = > Some ( Self ::All ) ,
SEARCH = > Some ( Self ::Search ) ,
DOCUMENTS_ALL = > Some ( Self ::DocumentsAll ) ,
DOCUMENTS_ADD = > Some ( Self ::DocumentsAdd ) ,
DOCUMENTS_GET = > Some ( Self ::DocumentsGet ) ,
DOCUMENTS_DELETE = > Some ( Self ::DocumentsDelete ) ,
INDEXES_ALL = > Some ( Self ::IndexesAll ) ,
INDEXES_CREATE = > Some ( Self ::IndexesAdd ) ,
INDEXES_GET = > Some ( Self ::IndexesGet ) ,
INDEXES_UPDATE = > Some ( Self ::IndexesUpdate ) ,
INDEXES_DELETE = > Some ( Self ::IndexesDelete ) ,
2022-10-24 20:49:39 +08:00
INDEXES_SWAP = > Some ( Self ::IndexesSwap ) ,
2022-10-12 22:10:28 +08:00
TASKS_ALL = > Some ( Self ::TasksAll ) ,
2022-10-18 20:48:40 +08:00
TASKS_CANCEL = > Some ( Self ::TasksCancel ) ,
TASKS_DELETE = > Some ( Self ::TasksDelete ) ,
2022-10-12 22:10:28 +08:00
TASKS_GET = > Some ( Self ::TasksGet ) ,
SETTINGS_ALL = > Some ( Self ::SettingsAll ) ,
SETTINGS_GET = > Some ( Self ::SettingsGet ) ,
SETTINGS_UPDATE = > Some ( Self ::SettingsUpdate ) ,
STATS_ALL = > Some ( Self ::StatsAll ) ,
STATS_GET = > Some ( Self ::StatsGet ) ,
METRICS_ALL = > Some ( Self ::MetricsAll ) ,
METRICS_GET = > Some ( Self ::MetricsGet ) ,
DUMPS_ALL = > Some ( Self ::DumpsAll ) ,
DUMPS_CREATE = > Some ( Self ::DumpsCreate ) ,
VERSION = > Some ( Self ::Version ) ,
KEYS_CREATE = > Some ( Self ::KeysAdd ) ,
KEYS_GET = > Some ( Self ::KeysGet ) ,
KEYS_UPDATE = > Some ( Self ::KeysUpdate ) ,
KEYS_DELETE = > Some ( Self ::KeysDelete ) ,
_otherwise = > None ,
}
}
pub const fn repr ( & self ) -> u8 {
* self as u8
}
}
pub mod actions {
use super ::Action ::* ;
pub ( crate ) const ALL : u8 = All . repr ( ) ;
pub const SEARCH : u8 = Search . repr ( ) ;
pub const DOCUMENTS_ALL : u8 = DocumentsAll . repr ( ) ;
pub const DOCUMENTS_ADD : u8 = DocumentsAdd . repr ( ) ;
pub const DOCUMENTS_GET : u8 = DocumentsGet . repr ( ) ;
pub const DOCUMENTS_DELETE : u8 = DocumentsDelete . repr ( ) ;
pub const INDEXES_ALL : u8 = IndexesAll . repr ( ) ;
pub const INDEXES_CREATE : u8 = IndexesAdd . repr ( ) ;
pub const INDEXES_GET : u8 = IndexesGet . repr ( ) ;
pub const INDEXES_UPDATE : u8 = IndexesUpdate . repr ( ) ;
pub const INDEXES_DELETE : u8 = IndexesDelete . repr ( ) ;
2022-10-17 22:30:18 +08:00
pub const INDEXES_SWAP : u8 = IndexesSwap . repr ( ) ;
2022-10-12 22:10:28 +08:00
pub const TASKS_ALL : u8 = TasksAll . repr ( ) ;
2022-10-18 20:48:40 +08:00
pub const TASKS_CANCEL : u8 = TasksCancel . repr ( ) ;
2022-10-13 17:09:00 +08:00
pub const TASKS_DELETE : u8 = TasksDelete . repr ( ) ;
2022-10-12 22:10:28 +08:00
pub const TASKS_GET : u8 = TasksGet . repr ( ) ;
pub const SETTINGS_ALL : u8 = SettingsAll . repr ( ) ;
pub const SETTINGS_GET : u8 = SettingsGet . repr ( ) ;
pub const SETTINGS_UPDATE : u8 = SettingsUpdate . repr ( ) ;
pub const STATS_ALL : u8 = StatsAll . repr ( ) ;
pub const STATS_GET : u8 = StatsGet . repr ( ) ;
pub const METRICS_ALL : u8 = MetricsAll . repr ( ) ;
pub const METRICS_GET : u8 = MetricsGet . repr ( ) ;
pub const DUMPS_ALL : u8 = DumpsAll . repr ( ) ;
pub const DUMPS_CREATE : u8 = DumpsCreate . repr ( ) ;
pub const VERSION : u8 = Version . repr ( ) ;
pub const KEYS_CREATE : u8 = KeysAdd . repr ( ) ;
pub const KEYS_GET : u8 = KeysGet . repr ( ) ;
pub const KEYS_UPDATE : u8 = KeysUpdate . repr ( ) ;
pub const KEYS_DELETE : u8 = KeysDelete . repr ( ) ;
}