aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/access')
-rw-r--r--src/access/rules.rs53
1 files changed, 53 insertions, 0 deletions
diff --git a/src/access/rules.rs b/src/access/rules.rs
index 0de901a..320ccd8 100644
--- a/src/access/rules.rs
+++ b/src/access/rules.rs
@@ -215,6 +215,59 @@ pub(crate) fn judge(doc: &Document, epoch: Epoch, change: &Change<'_>) -> Result
Ok(())
}
+/// `hash`, which `doc` (of `epoch`) holds, judged by its rules now, as received: why
+/// they refuse it, if they do; None if `doc` doesn't hold it. A change this node just
+/// made, before it leaves (`AppState::mutate_doc_for`), or one a peer says it refused
+/// (`swarm::refusals`).
+pub(crate) fn judge_held(
+ doc: &crate::document::Document,
+ epoch: Epoch,
+ hash: &ChangeHash,
+) -> Option<Result<(), String>> {
+ let change = doc.get_change_by_hash(hash)?;
+ // An epoch's root is what the document is: never refused, whatever a peer says.
+ if change.deps().is_empty() {
+ return Some(Ok(()));
+ }
+ let decoded = change.decode();
+ let ops = crate::document::inspect::Inspector::new(doc)
+ .ops(std::slice::from_ref(&decoded))
+ .pop()
+ .unwrap_or_default();
+ let paths = ops.iter().map(|op| op.path.clone()).collect();
+ let committer = doc
+ .get_author_for_actor(change.actor_id())
+ .and_then(|author| {
+ std::str::from_utf8(author.as_bytes())
+ .ok()
+ .map(str::to_owned)
+ });
+ let user = change
+ .message()
+ .and_then(crate::document::replica::user_of)
+ .map(str::to_owned);
+ let deps = change.deps().to_vec();
+ let judged = judge(
+ doc,
+ epoch,
+ &Change {
+ hash: *hash,
+ deps: &deps,
+ seen: &deps,
+ committer: committer.as_deref(),
+ user: user.as_deref(),
+ paths: &paths,
+ ops: &ops,
+ },
+ );
+ Some(match judged {
+ Ok(()) => Ok(()),
+ Err(Refusal::Rule(why)) => Err(why),
+ // Its dependencies are in the document: it is.
+ Err(Refusal::Unready) => Ok(()),
+ })
+}
+
/// Where values are declared sealed (`declared`), `ops` write only sealed values as
/// declared, judged at `at`, as their writer saw it (`sealed::check`): at such a place, a
/// string put there that is one (or deleting what is there); nothing within one; nothing