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

ambee/giterated

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

Add repository setings

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨3b20354

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