1use core::fmt;
13use std::collections::HashMap;
14use std::collections::HashSet;
15use std::sync::Arc;
16
17use crate::errors::*;
18#[allow(unused_imports)]
19use crate::log::*;
20use crate::store::Store;
21use crate::types::*;
22
23impl RepositoryV0 {
24 pub fn new_with_meta(id: &PubKey, metadata: &Vec<u8>) -> RepositoryV0 {
25 RepositoryV0 {
26 id: id.clone(),
27 metadata: metadata.clone(),
28 verification_program: vec![],
29 fork_of: vec![],
30 creator: None,
31 }
32 }
33}
34
35impl Repository {
36 pub fn new(id: &RepoId) -> Self {
37 Repository::V0(RepositoryV0 {
38 id: id.clone(),
39 verification_program: vec![],
40 creator: None,
41 fork_of: vec![],
42 metadata: vec![],
43 })
44 }
45 pub fn new_with_meta(id: &PubKey, metadata: &Vec<u8>) -> Repository {
46 Repository::V0(RepositoryV0::new_with_meta(id, metadata))
47 }
48 pub fn id(&self) -> &PubKey {
49 match self {
50 Self::V0(v0) => &v0.id,
51 }
52 }
53}
54
55#[derive(Debug)]
56pub struct UserInfo {
57 pub permissions: HashMap<PermissionV0, Vec<u8>>,
59 pub id: UserId,
60}
61
62impl UserInfo {
63 pub fn has_any_perm(&self, perms: &HashSet<PermissionV0>) -> Result<(), NgError> {
64 if self.has_perm(&PermissionV0::Owner).is_ok() {
66 return Ok(());
67 }
68 let is_admin = self.has_perm(&PermissionV0::Admin).is_ok();
69 let has_perms: HashSet<&PermissionV0> = self.permissions.keys().collect();
72 for perm in perms {
74 if is_admin && perm.is_delegated_by_admin() || has_perms.contains(perm) {
75 return Ok(());
76 }
77 }
78 Err(NgError::PermissionDenied)
82 }
83 pub fn has_perm(&self, perm: &PermissionV0) -> Result<&Vec<u8>, NgError> {
84 self.permissions.get(perm).ok_or(NgError::PermissionDenied)
85 }
86}
87
88#[derive(Debug)]
89pub struct BranchInfo {
90 pub id: BranchId,
91
92 pub branch_type: BranchType,
93
94 pub topic: TopicId,
95
96 pub topic_priv_key: Option<BranchWriteCapSecret>,
97
98 pub read_cap: ReadCap,
99
100 pub current_heads: Vec<ObjectRef>,
101
102 pub commits_nbr: u64,
103}
104
105#[derive(Debug)]
107pub struct Repo {
108 pub id: RepoId,
109 pub repo_def: Repository,
111
112 pub read_cap: Option<ReadCap>,
113
114 pub write_cap: Option<RepoWriteCapSecret>,
115
116 pub signer: Option<SignerCap>,
117
118 pub members: HashMap<Digest, UserInfo>,
119
120 pub branches: HashMap<BranchId, BranchInfo>,
121
122 pub opened_branches: HashMap<BranchId, bool>,
126
127 pub store: Arc<Store>,
138}
139
140impl fmt::Display for Repo {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 writeln!(f, "====== Repo ====== {}", self.id)?;
143
144 write!(f, "== repo_def: {}", self.repo_def)?;
145
146 if self.signer.is_some() {
147 writeln!(f, "== signer: {:?}", self.signer)?;
148 }
149
150 writeln!(f, "== members: {:?}", self.members)?;
151
152 Ok(())
153 }
154}
155
156impl Repo {
157 #[cfg(any(test, feature = "testing"))]
158 #[allow(deprecated)]
159 pub fn new_with_perms(perms: &[PermissionV0], store: Arc<Store>) -> Self {
160 let pub_key = PubKey::nil();
161 Self::new_with_member(&pub_key, &pub_key, perms, store)
162 }
163
164 pub fn update_branch_current_heads(
165 &mut self,
166 branch: &BranchId,
167 commit_ref: ObjectRef,
168 past: Vec<ObjectRef>,
169 ) -> Result<Vec<ObjectRef>, VerifierError> {
170 if let Some(branch) = self.branches.get_mut(branch) {
172 let mut set: HashSet<&ObjectRef> = HashSet::from_iter(branch.current_heads.iter());
173 for p in past {
174 set.remove(&p);
175 }
176 branch.current_heads = set.into_iter().cloned().collect();
177 branch.current_heads.push(commit_ref);
178 branch.commits_nbr += 1;
179 Ok(branch.current_heads.to_vec())
181 } else {
182 Err(VerifierError::BranchNotFound)
183 }
184 }
185
186 pub fn new_with_member(
187 repo_id: &PubKey,
188 member: &UserId,
189 perms: &[PermissionV0],
190 store: Arc<Store>,
191 ) -> Self {
192 let mut members = HashMap::new();
193 let permissions = HashMap::from_iter(
194 perms
195 .iter()
196 .map(|p| (*p, vec![]))
197 .collect::<Vec<(PermissionV0, Vec<u8>)>>()
198 .iter()
199 .cloned(),
200 );
201 let overlay = store.get_store_repo().overlay_id_for_read_purpose();
202 let member_hash = CommitContent::author_digest(member, overlay);
203 members.insert(
205 member_hash,
206 UserInfo {
207 id: *member,
208 permissions,
209 },
210 );
211 Self {
212 id: repo_id.clone(),
213 repo_def: Repository::new(&repo_id),
214 members,
215 store,
216 signer: None,
217 read_cap: None,
218 write_cap: None,
219 branches: HashMap::new(),
220 opened_branches: HashMap::new(),
221 }
223 }
224
225 pub fn verify_permission(&self, commit: &Commit) -> Result<(), NgError> {
226 let content_author = commit.content_v0().author;
227 let body = commit.load_body(&self.store)?;
228 match self.members.get(&content_author) {
229 Some(info) => return info.has_any_perm(&body.required_permission()),
230 None => {}
231 }
232 Err(NgError::PermissionDenied)
233 }
234
235 pub fn member_pubkey(&self, hash: &Digest) -> Result<UserId, NgError> {
236 match self.members.get(hash) {
237 Some(user_info) => Ok(user_info.id),
238 None => Err(NgError::NotFound),
239 }
240 }
241
242 pub fn branch(&self, id: &BranchId) -> Result<&BranchInfo, NgError> {
243 self.branches.get(id).ok_or(NgError::BranchNotFound)
245 }
246
247 pub fn branch_mut(&mut self, id: &BranchId) -> Result<&mut BranchInfo, NgError> {
248 self.branches.get_mut(id).ok_or(NgError::BranchNotFound)
250 }
251
252 pub fn overlay_branch(&self) -> Option<&BranchInfo> {
253 for (_, branch) in self.branches.iter() {
254 if branch.branch_type == BranchType::Overlay {
255 return Some(branch);
256 }
257 }
258 None
259 }
260
261 pub fn user_branch(&self) -> Option<&BranchInfo> {
262 for (_, branch) in self.branches.iter() {
263 if branch.branch_type == BranchType::User {
264 return Some(branch);
265 }
266 }
267 None
268 }
269
270 pub fn main_branch(&self) -> Option<&BranchInfo> {
271 for (_, branch) in self.branches.iter() {
272 if branch.branch_type == BranchType::Main {
273 return Some(branch);
274 }
275 }
276 None
277 }
278
279 pub fn root_branch(&self) -> Option<&BranchInfo> {
280 for (_, branch) in self.branches.iter() {
281 if branch.branch_type == BranchType::Root {
282 return Some(branch);
283 }
284 }
285 None
286 }
287
288 pub fn overlay_branch_read_cap(&self) -> Option<&ReadCap> {
289 match self.overlay_branch() {
290 Some(bi) => Some(&bi.read_cap),
291 None => self.read_cap.as_ref(), }
293 }
294
295 pub fn branch_is_opened(&self, branch: &BranchId) -> bool {
296 self.opened_branches.contains_key(branch)
297 }
298
299 pub fn branch_is_opened_as_publisher(&self, branch: &BranchId) -> bool {
300 match self.opened_branches.get(branch) {
301 Some(val) => *val,
302 None => false,
303 }
304 }
305
306 }