aiscript_directive/route/
mod.rs

1use docs::Docs;
2use serde_json::Value;
3
4mod docs;
5use crate::{Directive, FromDirective};
6
7#[derive(Debug, Clone, Default)]
8pub struct RouteAnnotation {
9    pub auth: Auth,
10    pub docs: Option<Docs>,
11    pub sso_provider: Option<SsoProvider>,
12}
13
14#[derive(Debug, Copy, Clone, Default)]
15pub enum Auth {
16    Jwt,
17    Basic,
18    #[default]
19    None,
20}
21
22#[derive(Debug, Copy, Clone)]
23pub enum SsoProvider {
24    Facebook,
25    Google,
26    Discord,
27    GitHub,
28}
29
30impl SsoProvider {
31    pub fn as_str(&self) -> &'static str {
32        match self {
33            SsoProvider::Facebook => "facebook",
34            SsoProvider::Google => "google",
35            SsoProvider::Discord => "discord",
36            SsoProvider::GitHub => "github",
37        }
38    }
39}
40
41impl TryFrom<&String> for SsoProvider {
42    type Error = String;
43
44    fn try_from(value: &String) -> Result<Self, Self::Error> {
45        match value.as_ref() {
46            "facebook" => Ok(Self::Facebook),
47            "google" => Ok(Self::Google),
48            "discord" => Ok(Self::Discord),
49            "github" => Ok(Self::GitHub),
50            _ => Err(format!("Invalid SSO provider: `{value}`")),
51        }
52    }
53}
54
55impl RouteAnnotation {
56    pub fn is_auth_required(&self) -> bool {
57        match self.auth {
58            Auth::Jwt | Auth::Basic => true,
59            Auth::None => false,
60        }
61    }
62
63    pub fn is_jwt_auth(&self) -> bool {
64        matches!(self.auth, Auth::Jwt)
65    }
66
67    pub fn or(mut self, other: &RouteAnnotation) -> Self {
68        if matches!(self.auth, Auth::None) {
69            self.auth = other.auth;
70        }
71        if self.docs.is_none() {
72            self.docs = other.docs.clone()
73        }
74        self
75    }
76}
77
78impl FromDirective for Auth {
79    fn from_directive(directive: Directive) -> Result<Self, String> {
80        match directive.name.as_str() {
81            "auth" => Ok(Auth::Jwt),
82            "basic_auth" => Ok(Auth::Basic),
83            _ => Ok(Auth::None),
84        }
85    }
86}
87
88impl RouteAnnotation {
89    pub fn parse_directive(&mut self, directive: Directive) -> Result<(), String> {
90        match directive.name.as_str() {
91            "auth" | "basic_auth" => {
92                if matches!(self.auth, Auth::None) {
93                    self.auth = Auth::from_directive(directive)?;
94                } else {
95                    return Err("Duplicate auth directive".into());
96                }
97            }
98            "docs" => {
99                if self.docs.is_some() {
100                    return Err("Duplicate @docs directive".into());
101                } else {
102                    self.docs = Some(Docs::from_directive(directive)?);
103                }
104            }
105            "sso" => {
106                if let Some(Value::String(provider)) = directive.get_arg_value("provider") {
107                    self.sso_provider = Some(SsoProvider::try_from(provider)?);
108                } else {
109                    return Err("@sso required 'provider' argument.".into());
110                }
111            }
112            _ => {
113                return Err(format!("Invalid directive: @{}", directive.name));
114            }
115        }
116        Ok(())
117    }
118}