Skip to main content

didbot_scope/
account.rs

1//! `account:` scopes, as the permission spec defines them: one attribute of
2//! the account's hosting, and how much control over it.
3
4use std::fmt;
5
6use crate::parse::Syntax;
7use crate::{Scope, ScopeParseError};
8
9/// The part of an account's hosting an `account:` scope names.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum AccountAttr {
12    /// `email`: the account's email address, and whether it is confirmed.
13    Email,
14    /// `repo`: the whole repository, imported as a CAR file.
15    Repo,
16}
17
18/// How much control an `account:` scope grants over its attribute.
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub enum AccountAction {
21    /// `read`, which a scope naming no action grants.
22    Read,
23    /// `manage`, which includes `read`.
24    Manage,
25}
26
27impl AccountAttr {
28    fn parse(value: &str) -> Result<Self, ScopeParseError> {
29        match value {
30            "email" => Ok(Self::Email),
31            "repo" => Ok(Self::Repo),
32            other => Err(ScopeParseError::UnknownAttribute(other.to_owned())),
33        }
34    }
35}
36
37impl fmt::Display for AccountAttr {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.write_str(match self {
40            Self::Email => "email",
41            Self::Repo => "repo",
42        })
43    }
44}
45
46impl AccountAction {
47    fn parse(value: &str) -> Result<Self, ScopeParseError> {
48        match value {
49            "read" => Ok(Self::Read),
50            "manage" => Ok(Self::Manage),
51            other => Err(ScopeParseError::UnknownAction(other.to_owned())),
52        }
53    }
54
55    /// Whether this action allows everything `other` allows.
56    pub(crate) fn includes(self, other: Self) -> bool {
57        self == other || self == Self::Manage
58    }
59}
60
61/// Reads an `account:` atom: the attribute and one `action`, `read` when
62/// none is given.
63pub(crate) fn read(atom: &str, syntax: &mut Syntax<'_>) -> Result<Scope, ScopeParseError> {
64    let attr = syntax
65        .single("attr", true)
66        .filter(|attr| !attr.is_empty())
67        .ok_or_else(|| ScopeParseError::MissingValue(atom.to_owned()))?;
68    let action = syntax.single("action", false);
69    Ok(Scope::Account {
70        attr: AccountAttr::parse(&attr)?,
71        action: action
72            .as_deref()
73            .map(AccountAction::parse)
74            .transpose()?
75            .unwrap_or(AccountAction::Read),
76    })
77}