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

ambee/giterated

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

Implement `FromOperationState` for `AuthenticatedUser` and `AuthenticatedInstance`

Use `AuthenticatedUser` on repository requests so we can filter by privacy. Woohoo! Attempt to filter `UserRepositoriesRequest` responses by visibility to the requester.

Amber - ⁨2⁩ years ago

parent: tbd commit: ⁨75dcac3

⁨giterated-daemon/src/database_backend/handler.rs⁩ - ⁨13615⁩ bytes
Raw
1 use std::error::Error;
2
3 use futures_util::{future::BoxFuture, FutureExt};
4 use giterated_models::{
5 authenticated::UserAuthenticationToken,
6 error::{GetValueError, InstanceError, OperationError, RepositoryError, UserError},
7 instance::{
8 AuthenticationTokenRequest, Instance, RegisterAccountRequest, RepositoryCreateRequest,
9 },
10 object_backend::ObjectBackend,
11 repository::{
12 Commit, DefaultBranch, Description, LatestCommit, Repository,
13 RepositoryCommitBeforeRequest, RepositoryDiff, RepositoryDiffPatchRequest,
14 RepositoryDiffRequest, RepositoryFile, RepositoryFileFromIdRequest,
15 RepositoryFileFromPathRequest, RepositoryFileInspectRequest, RepositoryInfoRequest,
16 RepositorySummary, RepositoryView, Visibility,
17 },
18 settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError},
19 user::{User, UserRepositoriesRequest},
20 value::{AnyValue, GetValue},
21 };
22 use giterated_stack::{AuthenticatedUser, BackendWrapper, StackOperationState};
23
24 use super::DatabaseBackend;
25
26 pub fn user_get_repositories(
27 object: &User,
28 _operation: UserRepositoriesRequest,
29 state: DatabaseBackend,
30 operation_state: StackOperationState,
31 requester: Option<AuthenticatedUser>,
32 ) -> BoxFuture<'static, Result<Vec<RepositorySummary>, OperationError<UserError>>> {
33 let object = object.clone();
34
35 async move {
36 let mut user_backend = state.user_backend.lock().await;
37 let repositories_response = user_backend
38 .repositories_for_user(&requester, &object)
39 .await
40 .map_err(|e| OperationError::Internal(e.to_string()))?;
41
42 let mut repositories = vec![];
43
44 for repository in repositories_response {
45 if operation_state
46 .giterated_backend
47 .get_object::<Repository>(&repository.repository.to_string(), &operation_state)
48 .await
49 .is_ok()
50 {
51 repositories.push(repository);
52 }
53 }
54
55 Ok(repositories)
56 }
57 .boxed()
58 }
59
60 pub fn user_get_value(
61 object: &User,
62 operation: GetValue<AnyValue<User>>,
63 state: DatabaseBackend,
64 ) -> BoxFuture<'static, Result<AnyValue<User>, OperationError<GetValueError>>> {
65 let object = object.clone();
66
67 async move {
68 let mut user_backend = state.user_backend.lock().await;
69 let value = user_backend
70 .get_value(&object, &operation.value_name)
71 .await
72 .map_err(|e| OperationError::Internal(e.to_string()))?;
73
74 Ok(value)
75 }
76 .boxed()
77 }
78
79 pub fn user_get_setting(
80 object: &User,
81 operation: GetSetting<AnySetting>,
82 state: DatabaseBackend,
83 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
84 let object = object.clone();
85
86 async move {
87 let mut user_backend = state.user_backend.lock().await;
88 let value = user_backend
89 .get_setting(&object, &operation.setting_name)
90 .await
91 .map_err(|e| OperationError::Internal(e.to_string()))?;
92
93 Ok(value)
94 }
95 .boxed()
96 }
97
98 pub fn user_set_setting(
99 object: &User,
100 operation: SetSetting<AnySetting>,
101 state: DatabaseBackend,
102 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
103 let object = object.clone();
104
105 async move {
106 let mut user_backend = state.user_backend.lock().await;
107 let value = user_backend
108 .write_setting(&object, &operation.setting_name, &operation.value.0)
109 .await
110 .map_err(|e| OperationError::Internal(e.to_string()))?;
111
112 Ok(value)
113 }
114 .boxed()
115 }
116
117 pub fn repository_info(
118 object: &Repository,
119 operation: RepositoryInfoRequest,
120 state: DatabaseBackend,
121 operation_state: StackOperationState,
122 backend: BackendWrapper,
123 requester: Option<AuthenticatedUser>,
124 ) -> BoxFuture<'static, Result<RepositoryView, OperationError<RepositoryError>>> {
125 let object = object.clone();
126
127 async move {
128 let mut object = backend
129 .get_object::<Repository>(&object.to_string(), &operation_state)
130 .await
131 .unwrap();
132
133 let mut repository_backend = state.repository_backend.lock().await;
134 let tree = repository_backend
135 .repository_file_inspect(
136 &requester,
137 object.object(),
138 &RepositoryFileInspectRequest {
139 extra_metadata: operation.extra_metadata,
140 path: operation.path,
141 rev: operation.rev.clone(),
142 },
143 )
144 .await
145 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
146 drop(repository_backend);
147
148 let info = RepositoryView {
149 name: object.object().name.clone(),
150 owner: object.object().owner.clone(),
151 description: object.get::<Description>(&operation_state).await.ok(),
152 visibility: object
153 .get::<Visibility>(&operation_state)
154 .await
155 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
156 default_branch: object
157 .get::<DefaultBranch>(&operation_state)
158 .await
159 .map_err(|e| OperationError::Internal(format!("{:?}: {}", e.source(), e)))?,
160 // TODO: Can't be a simple get function, this needs to be returned alongside the tree as this differs depending on the rev and path.
161 latest_commit: object.get::<LatestCommit>(&operation_state).await.ok(),
162 tree_rev: operation.rev,
163 tree,
164 };
165
166 Ok(info)
167 }
168 .boxed()
169 }
170
171 pub fn repository_file_from_id(
172 object: &Repository,
173 operation: RepositoryFileFromIdRequest,
174 state: DatabaseBackend,
175 operation_state: StackOperationState,
176 backend: BackendWrapper,
177 requester: Option<AuthenticatedUser>,
178 ) -> BoxFuture<'static, Result<RepositoryFile, OperationError<RepositoryError>>> {
179 let object = object.clone();
180
181 async move {
182 let object = backend
183 .get_object::<Repository>(&object.to_string(), &operation_state)
184 .await
185 .unwrap();
186
187 let mut repository_backend = state.repository_backend.lock().await;
188 let file = repository_backend
189 .repository_file_from_id(
190 &requester,
191 object.object(),
192 &RepositoryFileFromIdRequest(operation.0),
193 )
194 .await
195 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
196 drop(repository_backend);
197
198 Ok(file)
199 }
200 .boxed()
201 }
202
203 pub fn repository_file_from_path(
204 object: &Repository,
205 operation: RepositoryFileFromPathRequest,
206 state: DatabaseBackend,
207 operation_state: StackOperationState,
208 backend: BackendWrapper,
209 requester: Option<AuthenticatedUser>,
210 ) -> BoxFuture<'static, Result<RepositoryFile, OperationError<RepositoryError>>> {
211 let object = object.clone();
212
213 async move {
214 let object = backend
215 .get_object::<Repository>(&object.to_string(), &operation_state)
216 .await
217 .unwrap();
218
219 let mut repository_backend = state.repository_backend.lock().await;
220 let file = repository_backend
221 .repository_file_from_path(
222 &requester,
223 object.object(),
224 &RepositoryFileFromPathRequest {
225 rev: operation.rev,
226 path: operation.path,
227 },
228 )
229 .await
230 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
231 drop(repository_backend);
232
233 Ok(file)
234 }
235 .boxed()
236 }
237
238 pub fn repository_diff(
239 object: &Repository,
240 operation: RepositoryDiffRequest,
241 state: DatabaseBackend,
242 operation_state: StackOperationState,
243 backend: BackendWrapper,
244 requester: Option<AuthenticatedUser>,
245 ) -> BoxFuture<'static, Result<RepositoryDiff, OperationError<RepositoryError>>> {
246 let object = object.clone();
247
248 async move {
249 let object = backend
250 .get_object::<Repository>(&object.to_string(), &operation_state)
251 .await
252 .unwrap();
253
254 let mut repository_backend = state.repository_backend.lock().await;
255 let diff = repository_backend
256 .repository_diff(&requester, object.object(), &operation)
257 .await
258 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
259 drop(repository_backend);
260
261 Ok(diff)
262 }
263 .boxed()
264 }
265
266 pub fn repository_diff_patch(
267 object: &Repository,
268 operation: RepositoryDiffPatchRequest,
269 state: DatabaseBackend,
270 operation_state: StackOperationState,
271 backend: BackendWrapper,
272 requester: Option<AuthenticatedUser>,
273 ) -> BoxFuture<'static, Result<String, OperationError<RepositoryError>>> {
274 let object = object.clone();
275
276 async move {
277 let object = backend
278 .get_object::<Repository>(&object.to_string(), &operation_state)
279 .await
280 .unwrap();
281
282 let mut repository_backend = state.repository_backend.lock().await;
283 let patch = repository_backend
284 .repository_diff_patch(&requester, object.object(), &operation)
285 .await
286 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
287 drop(repository_backend);
288
289 Ok(patch)
290 }
291 .boxed()
292 }
293
294 pub fn repository_commit_before(
295 object: &Repository,
296 operation: RepositoryCommitBeforeRequest,
297 state: DatabaseBackend,
298 operation_state: StackOperationState,
299 backend: BackendWrapper,
300 requester: Option<AuthenticatedUser>,
301 ) -> BoxFuture<'static, Result<Commit, OperationError<RepositoryError>>> {
302 let object = object.clone();
303
304 async move {
305 let object = backend
306 .get_object::<Repository>(&object.to_string(), &operation_state)
307 .await
308 .unwrap();
309
310 let mut repository_backend = state.repository_backend.lock().await;
311 let file = repository_backend
312 .repository_commit_before(&requester, object.object(), &operation)
313 .await
314 .map_err(|err| OperationError::Internal(format!("{:?}", err)))?;
315 drop(repository_backend);
316
317 Ok(file)
318 }
319 .boxed()
320 }
321
322 pub fn repository_get_value(
323 object: &Repository,
324 operation: GetValue<AnyValue<Repository>>,
325 state: DatabaseBackend,
326 ) -> BoxFuture<'static, Result<AnyValue<Repository>, OperationError<GetValueError>>> {
327 let object = object.clone();
328
329 async move {
330 let mut repository_backend = state.repository_backend.lock().await;
331 let value = repository_backend
332 .get_value(&object, &operation.value_name)
333 .await
334 .map_err(|e| {
335 OperationError::Internal(format!("error getting value: {}", e.to_string()))
336 })?;
337
338 Ok(value)
339 }
340 .boxed()
341 }
342
343 pub fn repository_get_setting(
344 object: &Repository,
345 operation: GetSetting<AnySetting>,
346 state: DatabaseBackend,
347 ) -> BoxFuture<'static, Result<AnySetting, OperationError<GetSettingError>>> {
348 let object = object.clone();
349
350 async move {
351 let mut repository_backend = state.repository_backend.lock().await;
352 let value = repository_backend
353 .get_setting(&object, &operation.setting_name)
354 .await
355 .map_err(|e| OperationError::Internal(e.to_string()))?;
356
357 Ok(value)
358 }
359 .boxed()
360 }
361
362 pub fn repository_set_setting(
363 object: &Repository,
364 operation: SetSetting<AnySetting>,
365 state: DatabaseBackend,
366 ) -> BoxFuture<'static, Result<(), OperationError<SetSettingError>>> {
367 let object = object.clone();
368
369 async move {
370 let mut repository_backend = state.repository_backend.lock().await;
371 let value = repository_backend
372 .write_setting(&object, &operation.setting_name, &operation.value.0)
373 .await
374 .map_err(|e| OperationError::Internal(e.to_string()))?;
375
376 Ok(value)
377 }
378 .boxed()
379 }
380
381 pub fn instance_authentication_request(
382 object: &Instance,
383 operation: AuthenticationTokenRequest,
384 state: DatabaseBackend,
385 ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> {
386 let object = object.clone();
387 async move {
388 let mut backend = state.user_backend.lock().await;
389
390 backend
391 .login(&object, operation)
392 .await
393 .map_err(|e| OperationError::Internal(e.to_string()))
394 }
395 .boxed()
396 }
397
398 pub fn instance_registration_request(
399 _object: &Instance,
400 operation: RegisterAccountRequest,
401 state: DatabaseBackend,
402 ) -> BoxFuture<'static, Result<UserAuthenticationToken, OperationError<InstanceError>>> {
403 async move {
404 let mut backend = state.user_backend.lock().await;
405
406 backend
407 .register(operation)
408 .await
409 .map_err(|e| OperationError::Internal(e.to_string()))
410 }
411 .boxed()
412 }
413
414 pub fn instance_create_repository_request(
415 _object: &Instance,
416 operation: RepositoryCreateRequest,
417 state: DatabaseBackend,
418 requester: AuthenticatedUser,
419 ) -> BoxFuture<'static, Result<Repository, OperationError<InstanceError>>> {
420 async move {
421 let mut backend = state.repository_backend.lock().await;
422
423 backend
424 .create_repository(&requester, &operation)
425 .await
426 .map_err(|e| OperationError::Internal(e.to_string()))
427 }
428 .boxed()
429 }
430