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⁩ - ⁨12961⁩ 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 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 .register_object::<Instance>()
88 .register_object::<Repository>()
89 .register_object::<User>();
90
91 GiteratedBackend::new(self.clone(), handlers)
92 }
93 }
94
95 impl Debug for DatabaseBackend {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("DatabaseBackend").finish()
98 }
99 }
100
101 // TODO: These should be on the stack
102 // These tests verify that the essential handling of the database backend is
103 // functional and correct.
104 #[cfg(test)]
105 mod test {
106 use std::{str::FromStr, sync::Arc};
107
108 use anyhow::Error;
109
110 use giterated_models::authenticated::UserAuthenticationToken;
111
112 use giterated_models::instance::{
113 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
114 };
115
116 use giterated_models::object_backend::ObjectBackend;
117
118 use giterated_models::repository::{
119 Commit, Description, Repository, RepositoryCommitBeforeRequest, RepositoryDiff,
120 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
121 RepositoryFileInspectRequest, RepositorySummary, RepositoryTreeEntry, RepositoryDiffPatchRequest,
122 };
123 use giterated_models::settings::AnySetting;
124 use giterated_models::user::{DisplayName, User};
125 use giterated_models::value::{AnyValue, GiteratedObjectValue};
126 use giterated_stack::handler::GiteratedBackend;
127 use giterated_stack::StackOperationState;
128 use serde_json::Value;
129 use tokio::sync::Mutex;
130
131 use crate::backend::{git::GitBackendError, AuthBackend, RepositoryBackend, UserBackend};
132
133 use super::DatabaseBackend;
134 pub struct TestUserDatabaseBackend;
135
136 #[async_trait::async_trait]
137 impl UserBackend for TestUserDatabaseBackend {
138 async fn get_value(&mut self, _user: &User, name: &str) -> Result<AnyValue<User>, Error> {
139 assert_eq!(name, DisplayName::value_name());
140
141 Ok(serde_json::from_slice(
142 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
143 )
144 .unwrap())
145 }
146 async fn get_setting(&mut self, _user: &User, _name: &str) -> Result<AnySetting, Error> {
147 Ok(serde_json::from_slice(
148 &serde_json::to_vec(&DisplayName(String::from("test"))).unwrap(),
149 )
150 .unwrap())
151 }
152 async fn write_setting(
153 &mut self,
154 _user: &User,
155 _name: &str,
156 _setting: &Value,
157 ) -> Result<(), Error> {
158 Ok(())
159 }
160 async fn exists(&mut self, user: &User) -> Result<bool, Error> {
161 Ok(user == &User::from_str("test_user:test.giterated.dev").unwrap())
162 }
163 async fn repositories_for_user(
164 &mut self,
165 _requester: Option<&User>,
166 _user: &User,
167 ) -> Result<Vec<RepositorySummary>, Error> {
168 todo!()
169 }
170 }
171
172 #[async_trait::async_trait]
173 impl AuthBackend for TestUserDatabaseBackend {
174 async fn register(
175 &mut self,
176 _request: RegisterAccountRequest,
177 ) -> Result<UserAuthenticationToken, Error> {
178 todo!()
179 }
180
181 async fn login(
182 &mut self,
183 _source: &Instance,
184 _request: AuthenticationTokenRequest,
185 ) -> Result<UserAuthenticationToken, Error> {
186 todo!()
187 }
188 }
189
190 pub struct TestUserRepositoryBackend;
191
192 #[async_trait::async_trait]
193 impl RepositoryBackend for TestUserRepositoryBackend {
194 async fn create_repository(
195 &mut self,
196 _user: &User,
197 _request: &RepositoryCreateRequest,
198 ) -> Result<Repository, GitBackendError> {
199 todo!()
200 }
201 async fn repository_file_inspect(
202 &mut self,
203 _requester: Option<&User>,
204 _repository: &Repository,
205 _request: &RepositoryFileInspectRequest,
206 ) -> Result<Vec<RepositoryTreeEntry>, Error> {
207 todo!()
208 }
209 async fn repository_file_from_id(
210 &mut self,
211 _requester: Option<&User>,
212 _repository: &Repository,
213 _request: &RepositoryFileFromIdRequest,
214 ) -> Result<RepositoryFile, Error> {
215 todo!()
216 }
217 async fn repository_diff(
218 &mut self,
219 _requester: Option<&User>,
220 _repository: &Repository,
221 _request: &RepositoryDiffRequest,
222 ) -> Result<RepositoryDiff, Error> {
223 todo!()
224 }
225 async fn repository_diff_patch(
226 &mut self,
227 _requester: Option<&User>,
228 _repository: &Repository,
229 _request: &RepositoryDiffPatchRequest,
230 ) -> Result<String, Error> {
231 todo!()
232 }
233 async fn repository_commit_before(
234 &mut self,
235 _requester: Option<&User>,
236 _repository: &Repository,
237 _request: &RepositoryCommitBeforeRequest,
238 ) -> Result<Commit, Error> {
239 todo!()
240 }
241 async fn get_value(
242 &mut self,
243 _repository: &Repository,
244 _name: &str,
245 ) -> Result<AnyValue<Repository>, Error> {
246 Ok(serde_json::from_slice(
247 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
248 )
249 .unwrap())
250 }
251 async fn get_setting(
252 &mut self,
253 _repository: &Repository,
254 _name: &str,
255 ) -> Result<AnySetting, Error> {
256 Ok(serde_json::from_slice(
257 &serde_json::to_vec(&Description(String::from("test"))).unwrap(),
258 )
259 .unwrap())
260 }
261 async fn write_setting(
262 &mut self,
263 _repository: &Repository,
264 _name: &str,
265 _setting: &Value,
266 ) -> Result<(), Error> {
267 Ok(())
268 }
269
270 async fn exists(&mut self, repository: &Repository) -> Result<bool, Error> {
271 // Ok(true)
272 Ok(repository
273 == &Repository::from_str(
274 "test_user:test.giterated.dev/[email protected]",
275 )
276 .unwrap())
277 }
278 }
279
280 fn test_backend() -> GiteratedBackend<DatabaseBackend> {
281 DatabaseBackend {
282 our_instance: Instance::from_str("testing.giterated.dev").unwrap(),
283 user_backend: Arc::new(Mutex::new(TestUserDatabaseBackend)) as _,
284 repository_backend: Arc::new(Mutex::new(TestUserRepositoryBackend)) as _,
285 }
286 .into_backend()
287 }
288
289 fn operation_state() -> StackOperationState {
290 todo!()
291 }
292
293 #[tokio::test]
294 async fn test_user_get() {
295 let backend = test_backend();
296 let operation_state = operation_state();
297
298 let mut user = backend
299 .get_object::<User>("test_user:test.giterated.dev", &operation_state)
300 .await
301 .expect("object should have been returned");
302
303 user.get::<DisplayName>(&operation_state)
304 .await
305 .expect("object value should have been returned");
306 }
307
308 #[tokio::test]
309 async fn test_user_get_setting() {
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_setting::<DisplayName>(&operation_state)
319 .await
320 .expect("object value should have been returned");
321 }
322
323 #[tokio::test]
324 async fn test_user_set_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.set_setting::<DisplayName>(DisplayName(String::from("test")), &operation_state)
334 .await
335 .expect("object value should have been returned");
336 }
337
338 #[tokio::test]
339 async fn test_respository_get() {
340 let backend = test_backend();
341 let operation_state = operation_state();
342
343 let mut repository = backend
344 .get_object::<Repository>(
345 "test_user:test.giterated.dev/[email protected]",
346 &operation_state,
347 )
348 .await
349 .expect("object should have been returned");
350
351 repository
352 .get::<Description>(&operation_state)
353 .await
354 .expect("object value should have been returned");
355 }
356
357 #[tokio::test]
358 async fn test_repository_get_setting() {
359 let backend = test_backend();
360 let operation_state = operation_state();
361
362 let mut repository = backend
363 .get_object::<Repository>(
364 "test_user:test.giterated.dev/[email protected]",
365 &operation_state,
366 )
367 .await
368 .expect("object should have been returned");
369
370 repository
371 .get_setting::<Description>(&operation_state)
372 .await
373 .expect("object value should have been returned");
374 }
375
376 #[tokio::test]
377 async fn test_repository_set_setting() {
378 let backend = test_backend();
379 let operation_state = operation_state();
380
381 let mut repository = backend
382 .get_object::<Repository>(
383 "test_user:test.giterated.dev/[email protected]",
384 &operation_state,
385 )
386 .await
387 .expect("object should have been returned");
388
389 repository
390 .set_setting::<Description>(Description(String::from("test")), &operation_state)
391 .await
392 .expect("object value should have been returned");
393 }
394 }
395