#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DocumentVariant {
Workspace,
Page,
Space,
Settings,
Unknown,
}
impl DocumentVariant {
pub const fn as_str(self) -> &'static str {
match self {
Self::Workspace => "workspace",
Self::Page => "page",
Self::Space => "space",
Self::Settings => "settings",
Self::Unknown => "unknown",
}
}
fn parse(value: &str) -> Option<Self> {
match value {
"page" => Some(Self::Page),
"space" => Some(Self::Space),
"settings" => Some(Self::Settings),
_ => None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CanonicalDocumentIdentity {
workspace_id: String,
doc_id: String,
variant: DocumentVariant,
}
impl CanonicalDocumentIdentity {
pub fn workspace_id(&self) -> &str {
&self.workspace_id
}
pub fn doc_id(&self) -> &str {
&self.doc_id
}
pub const fn variant(&self) -> DocumentVariant {
self.variant
}
pub const fn is_workspace(&self) -> bool {
matches!(self.variant, DocumentVariant::Workspace)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DocumentIdentityError {
Empty,
WorkspaceRequired,
InvalidFormat,
InvalidVariant,
DocumentRequired,
}
pub fn canonicalize_document_identity(
raw_id: &str,
workspace_hint: Option<&str>,
) -> Result<CanonicalDocumentIdentity, DocumentIdentityError> {
if raw_id.is_empty() {
return Err(DocumentIdentityError::Empty);
}
if workspace_hint.is_some_and(str::is_empty) {
return Err(DocumentIdentityError::WorkspaceRequired);
}
let parts = raw_id.split(':').collect::<Vec<_>>();
let (workspace, variant, doc_id) = match parts.as_slice() {
[value] => match workspace_hint {
Some(hint) if *value != hint => (hint, DocumentVariant::Unknown, *value),
_ => (*value, DocumentVariant::Workspace, *value),
},
[variant, doc_id] => {
let workspace = workspace_hint.ok_or(DocumentIdentityError::WorkspaceRequired)?;
let variant = DocumentVariant::parse(variant).ok_or(DocumentIdentityError::InvalidVariant)?;
(workspace, variant, *doc_id)
}
[workspace, variant, doc_id] => {
let variant = DocumentVariant::parse(variant).ok_or(DocumentIdentityError::InvalidVariant)?;
(workspace_hint.unwrap_or(workspace), variant, *doc_id)
}
[workspace, "space", "page", doc_id] => (workspace_hint.unwrap_or(workspace), DocumentVariant::Space, *doc_id),
_ => return Err(DocumentIdentityError::InvalidFormat),
};
if workspace.is_empty() {
return Err(DocumentIdentityError::WorkspaceRequired);
}
if !matches!(variant, DocumentVariant::Workspace) && doc_id.is_empty() {
return Err(DocumentIdentityError::DocumentRequired);
}
Ok(CanonicalDocumentIdentity {
workspace_id: workspace.to_string(),
doc_id: doc_id.to_string(),
variant,
})
}
#[cfg(test)]
#[path = "../tests/access_control/document_identity/tests.rs"]
mod tests;