Showing 5 changed files with 142 insertions and 6 deletions
giterated-daemon/src/backend/git.rs
@@ -8,7 +8,7 @@ use giterated_models::repository::{ | ||
8 | 8 | Commit, DefaultBranch, Description, IssueLabel, LatestCommit, Repository, |
9 | 9 | RepositoryFileInspectRequest, RepositoryIssue, RepositoryIssueLabelsRequest, |
10 | 10 | RepositoryIssuesCountRequest, RepositoryIssuesRequest, RepositoryObjectType, |
11 | RepositoryTreeEntry, RepositoryVisibility, Visibility, RepositoryFile, RepositoryFileFromIdRequest, RepositoryDiffRequest, RepositoryDiff, | |
11 | RepositoryTreeEntry, RepositoryVisibility, Visibility, RepositoryFile, RepositoryFileFromIdRequest, RepositoryDiffRequest, RepositoryDiff, RepositoryCommitBeforeRequest, | |
12 | 12 | }; |
13 | 13 | use giterated_models::settings::{AnySetting, Setting}; |
14 | 14 | use giterated_models::user::{User, UserParseError}; |
@@ -97,6 +97,10 @@ pub enum GitBackendError { | ||
97 | 97 | BlobNotFound(String), |
98 | 98 | #[error("Tree with ID `{0}` not found")] |
99 | 99 | TreeNotFound(String), |
100 | #[error("Commit with ID `{0}` not found")] | |
101 | CommitNotFound(String), | |
102 | #[error("Parent for commit with ID `{0}` not found")] | |
103 | CommitParentNotFound(String), | |
100 | 104 | #[error("Failed diffing tree with ID `{0}` to tree with ID `{1}`")] |
101 | 105 | FailedDiffing(String, String), |
102 | 106 | } |
@@ -174,6 +178,42 @@ impl GitBackend { | ||
174 | 178 | } |
175 | 179 | } |
176 | 180 | |
181 | pub async fn open_repository_and_check_permissions(&self, owner: &User, name: &str, requester: Option<&User>) -> Result<git2::Repository, GitBackendError> { | |
182 | let repository = match self | |
183 | .find_by_owner_user_name( | |
184 | // &request.owner.instance.url, | |
185 | owner, | |
186 | name, | |
187 | ) | |
188 | .await | |
189 | { | |
190 | Ok(repository) => repository, | |
191 | Err(err) => return Err(err), | |
192 | }; | |
193 | ||
194 | if let Some(requester) = requester { | |
195 | if !repository.can_user_view_repository(Some(requester)) { | |
196 | return Err(GitBackendError::RepositoryNotFound { | |
197 | owner_user: repository.owner_user.to_string(), | |
198 | name: repository.name.clone(), | |
199 | }); | |
200 | } | |
201 | } else if matches!(repository.visibility, RepositoryVisibility::Private) { | |
202 | info!("Unauthenticated"); | |
203 | // Unauthenticated users can never view private repositories | |
204 | ||
205 | return Err(GitBackendError::RepositoryNotFound { | |
206 | owner_user: repository.owner_user.to_string(), | |
207 | name: repository.name.clone(), | |
208 | }); | |
209 | } | |
210 | ||
211 | match repository.open_git2_repository(&self.repository_folder) { | |
212 | Ok(git) => Ok(git), | |
213 | Err(err) => return Err(err), | |
214 | } | |
215 | } | |
216 | ||
177 | 217 | // TODO: Find where this fits |
178 | 218 | // TODO: Cache this and general repository tree and invalidate select files on push |
179 | 219 | // TODO: Find better and faster technique for this |
@@ -787,6 +827,35 @@ impl RepositoryBackend for GitBackend { | ||
787 | 827 | patch, |
788 | 828 | }) |
789 | 829 | } |
830 | ||
831 | async fn repository_commit_before( | |
832 | &mut self, | |
833 | requester: Option<&User>, | |
834 | repository: &Repository, | |
835 | request: &RepositoryCommitBeforeRequest, | |
836 | ) -> Result<Commit, Error> { | |
837 | let git = self.open_repository_and_check_permissions(&repository.owner, &repository.name, requester).await?; | |
838 | ||
839 | // Parse the passed object id | |
840 | let oid = match git2::Oid::from_str(request.0.as_str()) { | |
841 | Ok(oid) => oid, | |
842 | Err(_) => return Err(Box::new(GitBackendError::InvalidObjectId(request.0.clone())).into()), | |
843 | }; | |
844 | ||
845 | // Find the commit using the parsed oid | |
846 | let commit = match git.find_commit(oid) { | |
847 | Ok(commit) => commit, | |
848 | Err(_) => return Err(Box::new(GitBackendError::CommitNotFound(oid.to_string())).into()), | |
849 | }; | |
850 | ||
851 | // Get the first parent it has | |
852 | let parent = match commit.parent(0) { | |
853 | Ok(parent) => Commit::from(parent), | |
854 | Err(_) => return Err(Box::new(GitBackendError::CommitParentNotFound(oid.to_string())).into()), | |
855 | }; | |
856 | ||
857 | Ok(parent) | |
858 | } | |
790 | 859 | } |
791 | 860 | |
792 | 861 | impl IssuesBackend for GitBackend { |
giterated-daemon/src/backend/mod.rs
@@ -18,7 +18,7 @@ use giterated_models::instance::{ | ||
18 | 18 | use giterated_models::repository::{ |
19 | 19 | IssueLabel, Repository, RepositoryFileInspectRequest, RepositoryIssue, |
20 | 20 | RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest, |
21 | RepositorySummary, RepositoryTreeEntry, RepositoryFileFromIdRequest, RepositoryFile, RepositoryDiffRequest, RepositoryDiff, | |
21 | RepositorySummary, RepositoryTreeEntry, RepositoryFileFromIdRequest, RepositoryFile, RepositoryDiffRequest, RepositoryDiff, Commit, RepositoryCommitBeforeRequest, | |
22 | 22 | }; |
23 | 23 | use giterated_models::settings::AnySetting; |
24 | 24 | use giterated_models::user::User; |
@@ -49,6 +49,12 @@ pub trait RepositoryBackend { | ||
49 | 49 | repository: &Repository, |
50 | 50 | request: &RepositoryDiffRequest, |
51 | 51 | ) -> Result<RepositoryDiff, Error>; |
52 | async fn repository_commit_before( | |
53 | &mut self, | |
54 | requester: Option<&User>, | |
55 | repository: &Repository, | |
56 | request: &RepositoryCommitBeforeRequest, | |
57 | ) -> Result<Commit, Error>; | |
52 | 58 | async fn get_value( |
53 | 59 | &mut self, |
54 | 60 | user: &Repository, |
giterated-daemon/src/database_backend/handler.rs
@@ -8,7 +8,7 @@ use giterated_models::{ | ||
8 | 8 | operation::{AnyOperation, GiteratedOperation}, |
9 | 9 | repository::{ |
10 | 10 | DefaultBranch, Description, LatestCommit, Repository, RepositoryFileInspectRequest, |
11 | RepositoryInfoRequest, RepositorySummary, RepositoryView, Visibility, RepositoryFile, RepositoryFileFromIdRequest, RepositoryDiff, RepositoryDiffRequest, | |
11 | RepositoryInfoRequest, RepositorySummary, RepositoryView, Visibility, RepositoryFile, RepositoryFileFromIdRequest, RepositoryDiff, RepositoryDiffRequest, RepositoryCommitBeforeRequest, Commit, | |
12 | 12 | }, |
13 | 13 | settings::{AnySetting, GetSetting, GetSettingError, SetSetting, SetSettingError}, |
14 | 14 | user::{User, UserRepositoriesRequest}, |
@@ -307,6 +307,34 @@ pub fn repository_diff( | ||
307 | 307 | }.boxed() |
308 | 308 | } |
309 | 309 | |
310 | pub fn repository_commit_before( | |
311 | object: &Repository, | |
312 | operation: RepositoryCommitBeforeRequest, | |
313 | state: DatabaseBackend, | |
314 | ) -> BoxFuture<'static, Result<Commit, OperationError<RepositoryError>>> { | |
315 | let object = object.clone(); | |
316 | ||
317 | async move { | |
318 | let object = state | |
319 | .get_object::<Repository>(&object.to_string()) | |
320 | .await | |
321 | .unwrap(); | |
322 | ||
323 | let mut repository_backend = state.repository_backend.lock().await; | |
324 | let file = repository_backend | |
325 | .repository_commit_before( | |
326 | None, | |
327 | object.object(), | |
328 | &operation, | |
329 | ) | |
330 | .await | |
331 | .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; | |
332 | drop(repository_backend); | |
333 | ||
334 | Ok(file) | |
335 | }.boxed() | |
336 | } | |
337 | ||
310 | 338 | pub fn repository_get_value( |
311 | 339 | object: &Repository, |
312 | 340 | operation: GetValue<AnyValue<Repository>>, |
giterated-daemon/src/database_backend/mod.rs
@@ -18,7 +18,7 @@ use crate::backend::{RepositoryBackend, UserBackend}; | ||
18 | 18 | |
19 | 19 | use self::handler::{ |
20 | 20 | repository_get_setting, repository_get_value, repository_info, repository_set_setting, |
21 | user_get_repositories, user_get_setting, user_get_value, user_set_setting, OperationHandlers, repository_file_from_id, repository_diff, | |
21 | user_get_repositories, user_get_setting, user_get_value, user_set_setting, OperationHandlers, repository_file_from_id, repository_diff, repository_commit_before, | |
22 | 22 | }; |
23 | 23 | |
24 | 24 | #[derive(Clone, Debug)] |
@@ -119,6 +119,7 @@ impl ObjectBackend for DatabaseBackend { | ||
119 | 119 | .insert(repository_info) |
120 | 120 | .insert(repository_file_from_id) |
121 | 121 | .insert(repository_diff) |
122 | .insert(repository_commit_before) | |
122 | 123 | .insert(repository_get_value) |
123 | 124 | .insert(repository_get_setting) |
124 | 125 | .insert(repository_set_setting); |
@@ -257,7 +258,7 @@ mod test { | ||
257 | 258 | |
258 | 259 | use giterated_models::repository::{ |
259 | 260 | Description, Repository, RepositoryFileInspectRequest, RepositorySummary, |
260 | RepositoryTreeEntry, RepositoryFileFromIdRequest, RepositoryFile, RepositoryDiff, RepositoryDiffRequest | |
261 | RepositoryTreeEntry, RepositoryFileFromIdRequest, RepositoryFile, RepositoryDiff, RepositoryDiffRequest, RepositoryCommitBeforeRequest, Commit | |
261 | 262 | }; |
262 | 263 | use giterated_models::settings::AnySetting; |
263 | 264 | use giterated_models::user::{DisplayName, User}; |
@@ -359,6 +360,14 @@ mod test { | ||
359 | 360 | ) -> Result<RepositoryDiff, Error> { |
360 | 361 | todo!() |
361 | 362 | } |
363 | async fn repository_commit_before( | |
364 | &mut self, | |
365 | requester: Option<&User>, | |
366 | repository: &Repository, | |
367 | request: &RepositoryCommitBeforeRequest, | |
368 | ) -> Result<Commit, Error> { | |
369 | todo!() | |
370 | } | |
362 | 371 | async fn get_value( |
363 | 372 | &mut self, |
364 | 373 | _repository: &Repository, |
giterated-models/src/repository/operations.rs
@@ -7,7 +7,7 @@ use crate::{ | ||
7 | 7 | operation::GiteratedOperation, |
8 | 8 | }; |
9 | 9 | |
10 | use super::{IssueLabel, Repository, RepositoryIssue, RepositoryTreeEntry, RepositoryView, RepositoryFile, RepositoryDiff}; | |
10 | use super::{IssueLabel, Repository, RepositoryIssue, RepositoryTreeEntry, RepositoryView, RepositoryFile, RepositoryDiff, Commit}; | |
11 | 11 | |
12 | 12 | /// A request to get a repository's information. |
13 | 13 | /// |
@@ -67,6 +67,23 @@ impl GiteratedOperation<Repository> for RepositoryDiffRequest { | ||
67 | 67 | type Failure = RepositoryError; |
68 | 68 | } |
69 | 69 | |
70 | /// A request to get the commit before the one with the passed id | |
71 | /// | |
72 | /// # Authentication | |
73 | /// - Instance Authentication | |
74 | /// - Validate request against the `issued_for` public key | |
75 | /// - Validate User token against the user's instance's public key | |
76 | /// # Authorization | |
77 | /// - User Authorization | |
78 | /// - Potential User permissions checks | |
79 | #[derive(Clone, Debug, Serialize, Deserialize)] | |
80 | pub struct RepositoryCommitBeforeRequest(pub String); | |
81 | ||
82 | impl GiteratedOperation<Repository> for RepositoryCommitBeforeRequest { | |
83 | type Success = Commit; | |
84 | type Failure = RepositoryError; | |
85 | } | |
86 | ||
70 | 87 | #[derive(Clone, Debug, Serialize, Deserialize)] |
71 | 88 | pub struct RepositoryIssuesCountRequest; |
72 | 89 | |
@@ -163,6 +180,13 @@ impl<B: ObjectBackend + std::fmt::Debug> Object<'_, Repository, B> { | ||
163 | 180 | self.request::<RepositoryDiffRequest>(RepositoryDiffRequest { old_id, new_id }).await |
164 | 181 | } |
165 | 182 | |
183 | pub async fn commit_before( | |
184 | &mut self, | |
185 | id: String, | |
186 | ) -> Result<Commit, OperationError<RepositoryError>> { | |
187 | self.request::<RepositoryCommitBeforeRequest>(RepositoryCommitBeforeRequest(id)).await | |
188 | } | |
189 | ||
166 | 190 | // pub async fn issues_count(&mut self) -> Result<u64, OperationError<RepositoryError>> { |
167 | 191 | // self.request::<RepositoryIssuesCountRequest>(RepositoryIssuesCountRequest) |
168 | 192 | // .await |