1use crate::engine::SharedEngine;
4use crate::plugin::ScopeAuthState;
5use crate::types::{Ability, Capabilities, Membership, ResourceRef, ScopeRef};
6use sova_core::{Error, Request, Result};
7use sova_db::DbExt;
8
9pub trait ScopeExt {
10 fn scope_engine(&self) -> Result<SharedEngine>;
11 fn scope_authorize(
12 &self,
13 scope: ScopeRef,
14 user_id: i64,
15 ability: Ability,
16 resource: Option<ResourceRef>,
17 ) -> impl std::future::Future<Output = Result<Capabilities>> + Send;
18 fn scope_effective(
19 &self,
20 scope: ScopeRef,
21 user_id: i64,
22 resource: Option<ResourceRef>,
23 ) -> impl std::future::Future<Output = Result<Capabilities>> + Send;
24 fn scope_membership(
25 &self,
26 scope: ScopeRef,
27 user_id: i64,
28 ) -> impl std::future::Future<Output = Result<Membership>> + Send;
29}
30
31impl ScopeExt for Request {
32 fn scope_engine(&self) -> Result<SharedEngine> {
33 self.try_state::<ScopeAuthState>()
34 .map(|s| s.engine.clone())
35 .ok_or_else(|| Error::Internal("ScopeAuth plugin not installed".into()))
36 }
37
38 async fn scope_authorize(
39 &self,
40 scope: ScopeRef,
41 user_id: i64,
42 ability: Ability,
43 resource: Option<ResourceRef>,
44 ) -> Result<Capabilities> {
45 let engine = self.scope_engine()?;
46 let db = self.db().clone();
47 engine.authorize(&db, scope, user_id, ability, resource).await
48 }
49
50 async fn scope_effective(
51 &self,
52 scope: ScopeRef,
53 user_id: i64,
54 resource: Option<ResourceRef>,
55 ) -> Result<Capabilities> {
56 let engine = self.scope_engine()?;
57 let db = self.db().clone();
58 engine.effective(&db, scope, user_id, resource).await
59 }
60
61 async fn scope_membership(&self, scope: ScopeRef, user_id: i64) -> Result<Membership> {
62 let engine = self.scope_engine()?;
63 let db = self.db().clone();
64 engine.require_member(&db, scope, user_id).await
65 }
66}