JavaScript is disabled, refresh for a better experience. ambee/giterated

ambee/giterated

Git repository hosting, collaboration, and discovery for the Fediverse.

Add authentication back into the operation states

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨97a26fd

⁨giterated-daemon/src/database_backend/mod.rs⁩ - ⁨13615⁩ bytes
Raw
1 pub mod handler;
2
3 use std::sync::Arc;
4
5 use giterated_models::error::OperationError;
6 use giterated_models::instance::Instance;
7 use giterated_models::object::{GiteratedObject, Object, ObjectRequestError};
8 use giterated_models::object_backend::ObjectBackend;
9 use giterated_models::operation::GiteratedOperation;
10 use giterated_models::repository::Repository;
11 use giterated_models::user::User;
12 use giterated_stack::handler::GiteratedBackend;
13 use giterated_stack::{OperationHandlers, StackOperationState};
14 use std::fmt::Debug;
15 use tokio::sync::Mutex;
16
17 use crate::backend::{RepositoryBackend, UserBackend};
18
19 use self::handler::{
20 instance_authentication_request, instance_create_repository_request,
21 instance_registration_request, repository_commit_before, repository_diff,
22 repository_diff_patch, repository_file_from_id, repository_file_from_path,
23 repository_get_setting, repository_get_value, repository_info, repository_set_setting,
24 user_get_repositories, user_get_setting, user_get_value, user_set_setting,
25 };
26
27 #[derive(Clone, Debug)]
28 pub struct Foobackend {}
29
30 #[async_trait::async_trait]
31 impl ObjectBackend<StackOperationState> for Foobackend {
32 async fn object_operation<O: GiteratedObject + Debug, D: GiteratedOperation<O> + Debug>(
33 &self,
34 _object: O,
35 _operation: &str,
36 _payload: D,
37 _operation_state: &StackOperationState,
38 ) -> Result<D::Success, OperationError<D::Failure>> {
39 // We don't handle operations with this backend
40 Err(OperationError::Unhandled)
41 }
42
43 async fn get_object<O: GiteratedObject + Debug>(
44 &self,
45 _object_str: &str,
46 _operation_state: &StackOperationState,
47 ) -> Result<Object<StackOperationState, O, Self>, OperationError<ObjectRequestError>> {
48 Err(OperationError::Unhandled)
49 }
50 }
51
52 /// A backend implementation which attempts to resolve data from the instance's database.
53 #[derive(Clone)]
54 pub struct DatabaseBackend {
55 pub(self) our_instance: Instance,
56 pub(self) user_backend: Arc<Mutex<dyn UserBackend + Send>>,
57 pub(self) repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
58 }
59
60 impl DatabaseBackend {
61 pub fn new(
62 instance: Instance,
63 user_backend: Arc<Mutex<dyn UserBackend + Send>>,
64 repository_backend: Arc<Mutex<dyn RepositoryBackend + Send>>,
65 ) -> Self {
66 Self {
67 our_instance: instance,
68 user_backend,
69 repository_backend,
70 }
71 }
72
73 pub fn into_backend(&self) -> GiteratedBackend<Self> {
74 let mut handlers = OperationHandlers::default();
75
76 handlers
77 .insert(user_get_repositories)
78 .insert(user_get_value)
79 .insert(user_get_setting)
80 .insert(user_set_setting)
81 .insert(repository_info)
82 .insert(repository_file_from_id)
83 .insert(repository_file_from_path)
84 .insert(repository_diff)
85 .insert(repository_diff_patch)
86 .insert(repository_commit_before)
87 .insert(repository_get_value)
88 .insert(repository_get_setting)
89 .insert(repository_set_setting)
90 .insert(instance_registration_request)
91 .insert(instance_authentication_request)
92 .insert(instance_create_repository_request)
93 .register_object::<Instance>()
94 .register_object::<Repository>()
95 .register_object::<User>();
96
97 GiteratedBackend::new(self.clone(), handlers)
98 }
99 }
100
101 impl Debug for DatabaseBackend {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 f.debug_struct("DatabaseBackend").finish()
104 }
105 }
106
107 // TODO: These should be on the stack
108 // These tests verify that the essential handling of the database backend is
109 // functional and correct.
110 #[cfg(test)]
111 mod test {
112 use std::{str::FromStr, sync::Arc};
113
114 use anyhow::Error;
115
116 use giterated_models::authenticated::UserAuthenticationToken;
117
118 use giterated_models::instance::{
119 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
120 };
121
122 use giterated_models::object_backend::ObjectBackend;
123
124 use giterated_models::repository::{
125 Commit, Description, Repository, RepositoryCommitBeforeRequest, RepositoryDiff,
126 RepositoryDiffPatchRequest, RepositoryDiffRequest, RepositoryFile,
127 RepositoryFileFromIdRequest, RepositoryFileFromPathRequest, RepositoryFileInspectRequest,
128 RepositorySummary, RepositoryTreeEntry,
129 };
130 use giterated_models::settings::AnySetting;
131 use giterated_models::user::{DisplayName, User};
132 use giterated_models::value::{AnyValue, GiteratedObjectValue};
133 use giterated_stack::handler::GiteratedBackend;
134 use giterated_stack::StackOperationState;
135 use serde_json::Value;
136 use tokio::sync::Mutex;
137
138 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
139
140 use super::DatabaseBackend;
141 pub struct TestUserDatabaseBackend;
142
143 #[async_trait::async_trait]
144 impl UserBackend for TestUserDatabaseBackend {
145 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
146 assert_eq!(name, DisplayName::value_name());
147
148 Ok(serde_json::from_slice(
149 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
150 )
151 .unwrap())
152 }
153 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
154 Ok(serde_json::from_slice(
155 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
156 )
157 .unwrap())
158 }
159 async fn write_setting(
160 &mut self,
161 _user: &User,
162 _name: &str,
163 _setting: &Value,
164 ) -> Result<(), Error> {
165 Ok(())
166 }
167 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
168 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
169 }
170 async fn repositories_for_user(
171 &mut self,
172 _requester: Option<&User>,
173 _user: &User,
174 ) -> Result<Vec<RepositorySummary>, Error> {
175 todo!()
176 }
177 }
178
179 #[async_trait::async_trait]
180 impl AuthBackend for TestUserDatabaseBackend {
181 async fn register(
182 &mut self,
183 _request: RegisterAccountRequest,
184 ) -> Result<UserAuthenticationToken, Error> {
185 todo!()
186 }
187
188 async fn login(
189 &mut self,
190 _source: &Instance,
191 _request: AuthenticationTokenRequest,
192 ) -> Result<UserAuthenticationToken, Error> {
193 todo!()
194 }
195 }
196
197 pub struct TestUserRepositoryBackend;
198
199 #[async_trait::async_trait]
200 impl RepositoryBackend for TestUserRepositoryBackend {
201 async fn create_repository(
202 &mut self,
203 _user: &User,
204 _request: &RepositoryCreateRequest,
205 ) -> Result<Repository, GitBackendError> {
206 todo!()
207 }
208 async fn repository_file_inspect(
209 &mut self,
210 _requester: Option<&User>,
211 _repository: &Repository,
212 _request: &RepositoryFileInspectRequest,
213 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
214 todo!()
215 }
216 async fn repository_file_from_id(
217 &mut self,
218 _requester: Option<&User>,
219 _repository: &Repository,
220 _request: &RepositoryFileFromIdRequest,
221 ) -> Result<RepositoryFile, Error> {
222 todo!()
223 }
224 async fn repository_file_from_path(
225 &mut self,
226 _requester: Option<&User>,
227 _repository: &Repository,
228 _request: &RepositoryFileFromPathRequest,
229 ) -> Result<RepositoryFile, Error> {
230 todo!()
231 }
232 async fn repository_diff(
233 &mut self,
234 _requester: Option<&User>,
235 _repository: &Repository,
236 _request: &RepositoryDiffRequest,
237 ) -> Result<RepositoryDiff, Error> {
238 todo!()
239 }
240 async fn repository_diff_patch(
241 &mut self,
242 _requester: Option<&User>,
243 _repository: &Repository,
244 _request: &RepositoryDiffPatchRequest,
245 ) -> Result<String, Error> {
246 todo!()
247 }
248 async fn repository_commit_before(
249 &mut self,
250 _requester: Option<&User>,
251 _repository: &Repository,
252 _request: &RepositoryCommitBeforeRequest,
253 ) -> Result<Commit, Error> {
254 todo!()
255 }
256 async fn get_value(
257 &mut self,
258 _repository: &Repository,
259 _name: &str,
260 ) -> Result<AnyValue<Repository>, Error> {
261 Ok(serde_json::from_slice(
262 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
263 )
264 .unwrap())
265 }
266 async fn get_setting(
267 &mut self,
268 _repository: &Repository,
269 _name: &str,
270 ) -> Result<AnySetting, Error> {
271 Ok(serde_json::from_slice(
272 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
273 )
274 .unwrap())
275 }
276 async fn write_setting(
277 &mut self,
278 _repository: &Repository,
279 _name: &str,
280 _setting: &Value,
281 ) -> Result<(), Error> {
282 Ok(())
283 }
284
285 async fn exists(&mut self, repository: &Repository) -> Result<bool, Error> {
286 // Ok(true)
287 Ok(repository
288 == &Repository::from_str(
289 "test_user:test.giterated.dev/[email protected]",
290 )
291 .unwrap())
292 }
293 }
294
295 fn test_backend() -> GiteratedBackend<DatabaseBackend> {
296 DatabaseBackend {
297 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
298 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
299 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
300 }
301 .into_backend()
302 }
303
304 fn operation_state() -> StackOperationState {
305 todo!()
306 }
307
308 #[tokio::test]
309 async fn test_user_get() {
310 let backend = test_backend();
311 let operation_state = operation_state();
312
313 let mut user = backend
314 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
315 .await
316 .expect("object should have been returned");
317
318 user.get::<DisplayName>(&operation_state)
319 .await
320 .expect("object value should have been returned");
321 }
322
323 #[tokio::test]
324 async fn test_user_get_setting() {
325 let backend = test_backend();
326 let operation_state = operation_state();
327
328 let mut user = backend
329 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
330 .await
331 .expect("object should have been returned");
332
333 user.get_setting::<DisplayName>(&operation_state)
334 .await
335 .expect("object value should have been returned");
336 }
337
338 #[tokio::test]
339 async fn test_user_set_setting() {
340 let backend = test_backend();
341 let operation_state = operation_state();
342
343 let mut user = backend
344 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
345 .await
346 .expect("object should have been returned");
347
348 user.set_setting::<DisplayName>(DisplayName(String::from("test")), &operation_state)
349 .await
350 .expect("object value should have been returned");
351 }
352
353 #[tokio::test]
354 async fn test_respository_get() {
355 let backend = test_backend();
356 let operation_state = operation_state();
357
358 let mut repository = backend
359 .get_object::<Repository>(
360 "test_user:test.giterated.dev/[email protected]",
361 &operation_state,
362 )
363 .await
364 .expect("object should have been returned");
365
366 repository
367 .get::<Description>(&operation_state)
368 .await
369 .expect("object value should have been returned");
370 }
371
372 #[tokio::test]
373 async fn test_repository_get_setting() {
374 let backend = test_backend();
375 let operation_state = operation_state();
376
377 let mut repository = backend
378 .get_object::<Repository>(
379 "test_user:test.giterated.dev/[email protected]",
380 &operation_state,
381 )
382 .await
383 .expect("object should have been returned");
384
385 repository
386 .get_setting::<Description>(&operation_state)
387 .await
388 .expect("object value should have been returned");
389 }
390
391 #[tokio::test]
392 async fn test_repository_set_setting() {
393 let backend = test_backend();
394 let operation_state = operation_state();
395
396 let mut repository = backend
397 .get_object::<Repository>(
398 "test_user:test.giterated.dev/[email protected]",
399 &operation_state,
400 )
401 .await
402 .expect("object should have been returned");
403
404 repository
405 .set_setting::<Description>(Description(String::from("test")), &operation_state)
406 .await
407 .expect("object value should have been returned");
408 }
409 }
410