1use super::*;
2
3#[derive(Clone)]
4pub struct CoilAuth<E> {
5 engine: E,
6 tenant_id: i64,
7}
8
9impl<E> CoilAuth<E> {
10 pub fn new(engine: E, tenant_id: i64) -> Self {
11 Self { engine, tenant_id }
12 }
13
14 pub fn tenant_id(&self) -> i64 {
15 self.tenant_id
16 }
17
18 pub fn engine(&self) -> &E {
19 &self.engine
20 }
21
22 pub fn into_inner(self) -> E {
23 self.engine
24 }
25}
26
27impl<E> CoilAuth<E>
28where
29 E: RebacEngine,
30{
31 pub async fn apply_default_schema(&self) -> Result<(), RebacError> {
32 self.apply_model_package(&DefaultAuthModelPackage::default())
33 .await
34 }
35
36 pub async fn apply_model_package<P>(&self, package: &P) -> Result<(), RebacError>
37 where
38 P: AuthModelPackage + ?Sized,
39 {
40 self.engine
41 .apply_schema(self.tenant_id, package.schema().clone())
42 .await
43 }
44
45 pub async fn write(
46 &self,
47 updates: impl IntoIterator<Item = DefaultTupleUpdate>,
48 ) -> Result<(), RebacError> {
49 self.engine
50 .write_tuples(
51 self.tenant_id,
52 updates.into_iter().map(Into::into).collect(),
53 )
54 .await
55 }
56
57 pub async fn check(
58 &self,
59 subject: &DefaultSubject,
60 relation: Relation,
61 object: &Entity,
62 ) -> Result<bool, RebacError> {
63 let subject = subject.to_subject();
64 let object = object.to_object();
65
66 self.engine
67 .check(self.tenant_id, &subject, relation.as_str(), &object)
68 .await
69 }
70
71 pub async fn check_capability<P>(
72 &self,
73 package: &P,
74 subject: &DefaultSubject,
75 capability: Capability,
76 object: &Entity,
77 ) -> Result<bool, CoilAuthError>
78 where
79 P: AuthModelPackage + ?Sized,
80 {
81 let binding = package.resolve_binding(capability, object)?;
82 let subject = subject.to_subject();
83 let object = object.to_object();
84
85 Ok(self
86 .engine
87 .check(self.tenant_id, &subject, binding.relation.as_str(), &object)
88 .await?)
89 }
90
91 pub async fn check_default_capability(
92 &self,
93 subject: &DefaultSubject,
94 capability: Capability,
95 object: &Entity,
96 ) -> Result<bool, CoilAuthError> {
97 self.check_capability(
98 &DefaultAuthModelPackage::default(),
99 subject,
100 capability,
101 object,
102 )
103 .await
104 }
105
106 pub async fn explain_capability<P>(
107 &self,
108 package: &P,
109 subject: &DefaultSubject,
110 capability: Capability,
111 object: &Entity,
112 ) -> Result<CapabilityExplanation, CoilAuthError>
113 where
114 P: AuthModelPackage + ?Sized,
115 {
116 self.explain_capability_with_options(
117 package,
118 subject,
119 capability,
120 object,
121 ExplainOptions::default(),
122 )
123 .await
124 }
125
126 pub async fn explain_capability_with_options<P>(
127 &self,
128 package: &P,
129 subject: &DefaultSubject,
130 capability: Capability,
131 object: &Entity,
132 options: ExplainOptions,
133 ) -> Result<CapabilityExplanation, CoilAuthError>
134 where
135 P: AuthModelPackage + ?Sized,
136 {
137 let tuples = self
138 .engine
139 .read_tuples(self.tenant_id, None, None, None)
140 .await?;
141
142 build_capability_explanation(package, &tuples, subject, capability, object, options)
143 }
144
145 pub async fn explain_default_capability(
146 &self,
147 subject: &DefaultSubject,
148 capability: Capability,
149 object: &Entity,
150 ) -> Result<CapabilityExplanation, CoilAuthError> {
151 self.explain_default_capability_with_options(
152 subject,
153 capability,
154 object,
155 ExplainOptions::default(),
156 )
157 .await
158 }
159
160 pub async fn explain_default_capability_with_options(
161 &self,
162 subject: &DefaultSubject,
163 capability: Capability,
164 object: &Entity,
165 options: ExplainOptions,
166 ) -> Result<CapabilityExplanation, CoilAuthError> {
167 self.explain_capability_with_options(
168 &DefaultAuthModelPackage::default(),
169 subject,
170 capability,
171 object,
172 options,
173 )
174 .await
175 }
176
177 pub async fn check_many(
178 &self,
179 requests: impl IntoIterator<Item = AccessCheck>,
180 ) -> Result<Vec<bool>, RebacError> {
181 self.engine
182 .check_many(
183 self.tenant_id,
184 requests.into_iter().map(Into::into).collect(),
185 )
186 .await
187 }
188
189 pub async fn list_objects(
190 &self,
191 subject: &DefaultSubject,
192 relation: Relation,
193 namespace: Namespace,
194 ) -> Result<Vec<String>, RebacError> {
195 let subject = subject.to_subject();
196
197 self.engine
198 .list_objects(
199 self.tenant_id,
200 &subject,
201 relation.as_str(),
202 namespace.as_str(),
203 )
204 .await
205 }
206
207 pub async fn list_subject_ids(
208 &self,
209 object: &Entity,
210 relation: Relation,
211 namespace: Namespace,
212 ) -> Result<Vec<String>, RebacError> {
213 let object = object.to_object();
214
215 self.engine
216 .list_subjects(
217 self.tenant_id,
218 &object,
219 relation.as_str(),
220 namespace.as_str(),
221 )
222 .await
223 }
224}