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

ambee/giterated

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

Experimental repository diff structure

erremilia - ⁨2⁩ years ago

parent: tbd commit: ⁨0ef533d

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