radicle/cob/identity: Add has_active_sibling_accept helper
Add a helper method to check if a delegate has already voted on a sibling revision.
This commit is contained in:
parent
62f64744ad
commit
8e677a9d90
|
|
@ -363,6 +363,32 @@ impl Identity {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if the `delegate` has already accepted any child of the provided
|
||||||
|
/// `parent`.
|
||||||
|
///
|
||||||
|
/// The [`RevisionId`] is returned if one was found.
|
||||||
|
///
|
||||||
|
/// Used to enforce the invariant that no two sibling, active [`Revision`]s
|
||||||
|
/// should have an accepted vote from the same delegate.
|
||||||
|
pub(crate) fn has_active_sibling_accept(
|
||||||
|
&self,
|
||||||
|
parent: &RevisionId,
|
||||||
|
delegate: &Did,
|
||||||
|
) -> Option<RevisionId> {
|
||||||
|
self.children_of(parent).find_map(|child_id| {
|
||||||
|
self.revision(child_id).and_then(|child| {
|
||||||
|
if child.is_active() {
|
||||||
|
child
|
||||||
|
.accepted()
|
||||||
|
.any(|did| did == *delegate)
|
||||||
|
.then_some(*child_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl store::Cob for Identity {
|
impl store::Cob for Identity {
|
||||||
|
|
@ -2825,4 +2851,48 @@ mod test {
|
||||||
"Dave should be unauthorized because he was removed in the parent (A₂). Actual error: {err:?}"
|
"Dave should be unauthorized because he was removed in the parent (A₂). Actual error: {err:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn has_active_sibling_accept_returns_true_when_sibling_accepted() {
|
||||||
|
let network = Network::default();
|
||||||
|
let alice = &network.alice;
|
||||||
|
let bob = &network.bob;
|
||||||
|
|
||||||
|
// Setup: Alice adds Bob as delegate.
|
||||||
|
let mut alice_identity = Identity::load_mut(&*alice.repo, &alice.signer).unwrap();
|
||||||
|
let mut alice_doc = alice_identity.doc().clone().edit();
|
||||||
|
alice_doc.delegate(bob.signer.public_key().into());
|
||||||
|
let _a1 = alice_identity
|
||||||
|
.update(
|
||||||
|
cob::Title::new("Add Bob").unwrap(),
|
||||||
|
"",
|
||||||
|
&alice_doc.verified().unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Alice proposes a revision (child of current). Alice has an implicit accept.
|
||||||
|
let mut doc1 = alice_identity.doc().clone().edit();
|
||||||
|
doc1.visibility = Visibility::private([]);
|
||||||
|
let child = alice_identity
|
||||||
|
.update(
|
||||||
|
cob::Title::new("Child 1").unwrap(),
|
||||||
|
"",
|
||||||
|
&doc1.verified().unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let alice_did: Did = alice.signer.public_key().into();
|
||||||
|
|
||||||
|
// Alice has an accept on an Active child of current → true.
|
||||||
|
assert_eq!(
|
||||||
|
alice_identity.has_active_sibling_accept(&alice_identity.current, &alice_did),
|
||||||
|
Some(child)
|
||||||
|
);
|
||||||
|
// Bob does not → false.
|
||||||
|
let bob_did: Did = bob.signer.public_key().into();
|
||||||
|
assert_eq!(
|
||||||
|
alice_identity.has_active_sibling_accept(&alice_identity.current, &bob_did),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue