cob: Remove `author` from `Entry`

It was no longer used.

Signed-off-by: Alexis Sellier <alexis@radicle.xyz>
This commit is contained in:
Alexis Sellier 2022-11-30 12:18:52 +01:00
parent 5a47023ac0
commit dd7052926a
No known key found for this signature in database
20 changed files with 58 additions and 322 deletions

View File

@ -28,7 +28,6 @@ pub mod error {
use thiserror::Error;
use crate::signatures::error::Signatures;
use crate::trailers;
#[derive(Debug, Error)]
pub enum Create {
@ -69,8 +68,6 @@ pub mod error {
#[error("the 'change' found at '{0}' has more than one signature")]
TooManySignatures(Oid),
#[error(transparent)]
AuthorTrailer(#[from] trailers::error::InvalidAuthorTrailer),
#[error(transparent)]
ResourceTrailer(#[from] super::trailers::error::InvalidResourceTrailer),
#[error("non utf-8 characters in commit message")]
Utf8(#[from] FromUtf8Error),
@ -84,13 +81,11 @@ impl change::Storage for git2::Repository {
type LoadError = error::Load;
type ObjectId = Oid;
type Author = Oid;
type Resource = Oid;
type Signatures = Signature;
fn create<Signer>(
&self,
author: Option<Self::Author>,
resource: Self::Resource,
signer: &Signer,
spec: store::Create<Self::ObjectId>,
@ -119,20 +114,11 @@ impl change::Storage for git2::Repository {
Signature::from((*key, sig))
};
let id = write_commit(
self,
author,
resource,
tips,
message,
signature.clone(),
tree,
)?;
let id = write_commit(self, resource, tips, message, signature.clone(), tree)?;
Ok(Change {
id,
revision: revision.into(),
signature,
author,
resource,
manifest,
contents,
@ -141,7 +127,7 @@ impl change::Storage for git2::Repository {
fn load(&self, id: Self::ObjectId) -> Result<Change, Self::LoadError> {
let commit = Commit::read(self, id.into())?;
let (author, resource) = parse_trailers(commit.trailers())?;
let resource = parse_resource_trailer(commit.trailers())?;
let mut signatures = Signatures::try_from(&commit)?
.into_iter()
.collect::<Vec<_>>();
@ -160,7 +146,6 @@ impl change::Storage for git2::Repository {
id,
revision: tree.id().into(),
signature: signature.into(),
author,
resource,
manifest,
contents,
@ -168,26 +153,21 @@ impl change::Storage for git2::Repository {
}
}
fn parse_trailers<'a>(
mut trailers: impl Iterator<Item = &'a OwnedTrailer>,
) -> Result<(Option<Oid>, Oid), error::Load> {
let (author, resource) = trailers.try_fold((None, None), |(author, resource), trailer| {
match trailers::AuthorCommitTrailer::try_from(trailer) {
Ok(trailer) => Ok((Some(trailer.oid().into()), resource)),
Err(err) => match err {
trailers::error::InvalidAuthorTrailer::NoTrailer
| trailers::error::InvalidAuthorTrailer::NoValue => Ok((author, resource)),
trailers::error::InvalidAuthorTrailer::WrongToken => {
let resource = trailers::ResourceCommitTrailer::try_from(trailer)?;
Ok((author, Some(resource.oid().into())))
}
err => Err(error::Load::from(err)),
},
fn parse_resource_trailer<'a>(
trailers: impl Iterator<Item = &'a OwnedTrailer>,
) -> Result<Oid, error::Load> {
for trailer in trailers {
match trailers::ResourceCommitTrailer::try_from(trailer) {
Err(trailers::error::InvalidResourceTrailer::WrongToken) => {
continue;
}
Err(err) => return Err(err.into()),
Ok(resource) => return Ok(resource.oid().into()),
}
})?;
let resource = resource
.ok_or_else(|| error::Load::from(trailers::error::InvalidResourceTrailer::NoTrailer))?;
Ok((author, resource))
}
Err(error::Load::from(
trailers::error::InvalidResourceTrailer::NoTrailer,
))
}
fn load_manifest(
@ -223,7 +203,6 @@ fn load_contents(
fn write_commit<O>(
repo: &git2::Repository,
author: Option<O>,
resource: O,
tips: Vec<O>,
message: String,
@ -233,16 +212,12 @@ fn write_commit<O>(
where
O: AsRef<git2::Oid>,
{
let author = author.map(|author| *author.as_ref());
let resource = *resource.as_ref();
let mut parents = tips.iter().map(|o| *o.as_ref()).collect::<Vec<_>>();
parents.push(resource);
parents.extend(author);
let mut trailers: Vec<OwnedTrailer> =
vec![trailers::ResourceCommitTrailer::from(resource).into()];
trailers.extend(author.map(|author| trailers::AuthorCommitTrailer::from(author).into()));
let trailers: Vec<OwnedTrailer> = vec![trailers::ResourceCommitTrailer::from(resource).into()];
{
let author = repo.signature()?;

View File

@ -13,4 +13,4 @@ use crate::signatures::Signature;
/// A single change in the change graph. The layout of changes in the repository
/// is specified in the RFC (docs/rfc/0662-collaborative-objects.adoc)
/// under "Change Commits".
pub type Change = store::Change<Oid, Oid, Oid, Signature>;
pub type Change = store::Change<Oid, Oid, Signature>;

View File

@ -14,21 +14,16 @@ pub trait Storage {
type LoadError: Error + Send + Sync + 'static;
type ObjectId;
type Author;
type Resource;
type Signatures;
#[allow(clippy::type_complexity)]
fn create<Signer>(
&self,
author: Option<Self::Author>,
authority: Self::Resource,
signer: &Signer,
spec: Create<Self::ObjectId>,
) -> Result<
Change<Self::Author, Self::Resource, Self::ObjectId, Self::Signatures>,
Self::CreateError,
>
) -> Result<Change<Self::Resource, Self::ObjectId, Self::Signatures>, Self::CreateError>
where
Signer: crypto::Signer;
@ -36,10 +31,7 @@ pub trait Storage {
fn load(
&self,
id: Self::ObjectId,
) -> Result<
Change<Self::Author, Self::Resource, Self::ObjectId, Self::Signatures>,
Self::LoadError,
>;
) -> Result<Change<Self::Resource, Self::ObjectId, Self::Signatures>, Self::LoadError>;
}
pub struct Create<Id> {
@ -51,7 +43,7 @@ pub struct Create<Id> {
}
#[derive(Clone, Debug)]
pub struct Change<Author, Resource, Id, Signature> {
pub struct Change<Resource, Id, Signature> {
/// The content address of the `Change` itself.
pub id: Id,
/// The content address of the tree of the `Change`.
@ -59,9 +51,6 @@ pub struct Change<Author, Resource, Id, Signature> {
/// The cryptographic signature(s) and their public keys of the
/// authors.
pub signature: Signature,
/// The author of this change. The `Author` is expected to be a
/// content address to look up the identity of the author.
pub author: Option<Author>,
/// The parent resource that this change lives under. For example,
/// this change could be for a patch of a project.
pub resource: Resource,
@ -72,7 +61,7 @@ pub struct Change<Author, Resource, Id, Signature> {
pub contents: Contents,
}
impl<Author, Resource, Id, S> fmt::Display for Change<Author, Resource, Id, S>
impl<Resource, Id, S> fmt::Display for Change<Resource, Id, S>
where
Id: fmt::Display,
{
@ -81,15 +70,11 @@ where
}
}
impl<Author, Resource, Id, Signatures> Change<Author, Resource, Id, Signatures> {
impl<Resource, Id, Signatures> Change<Resource, Id, Signatures> {
pub fn id(&self) -> &Id {
&self.id
}
pub fn author(&self) -> &Option<Author> {
&self.author
}
pub fn typename(&self) -> &TypeName {
&self.manifest.typename
}
@ -103,7 +88,7 @@ impl<Author, Resource, Id, Signatures> Change<Author, Resource, Id, Signatures>
}
}
impl<A, R, Id> Change<A, R, Id, signatures::Signatures>
impl<R, Id> Change<R, Id, signatures::Signatures>
where
Id: AsRef<[u8]>,
{
@ -114,7 +99,7 @@ where
}
}
impl<A, R, Id> Change<A, R, Id, signatures::Signature>
impl<R, Id> Change<R, Id, signatures::Signature>
where
Id: AsRef<[u8]>,
{

View File

@ -37,7 +37,7 @@ impl ChangeGraph {
oid: &ObjectId,
) -> Option<ChangeGraph>
where
S: change::Storage<ObjectId = Oid, Author = Oid, Resource = Oid, Signatures = Signature>,
S: change::Storage<ObjectId = Oid, Resource = Oid, Signatures = Signature>,
{
log::info!("loading object '{}' '{}'", typename, oid);
let mut builder = GraphBuilder::default();
@ -170,7 +170,6 @@ impl GraphBuilder {
commit: object::Commit,
change: Change,
) -> impl Iterator<Item = (object::Commit, Oid)> + '_ {
let author_commit = *change.author();
let resource_commit = *change.resource();
let commit_id = commit.id;
if let Entry::Vacant(e) = self.node_indices.entry(commit_id) {
@ -178,10 +177,7 @@ impl GraphBuilder {
e.insert(ix);
}
commit.parents.into_iter().filter_map(move |parent| {
if Some(parent.id) != author_commit
&& parent.id != resource_commit
&& !self.has_edge(parent.id, commit_id)
{
if parent.id != resource_commit && !self.has_edge(parent.id, commit_id) {
Some((parent, commit_id))
} else {
None

View File

@ -67,7 +67,6 @@ fn evaluate_change(
Ok(history::Entry::new(
*change.id(),
change.signature.key,
*change.author(),
change.resource,
child_commits.iter().cloned(),
change.contents().clone(),

View File

@ -42,7 +42,6 @@ impl History {
pub(crate) fn new_from_root<Id>(
id: Id,
actor: PublicKey,
author: Option<Oid>,
resource: Oid,
contents: Contents,
) -> Self
@ -53,7 +52,6 @@ impl History {
let root_entry = Entry {
id,
actor,
author,
resource,
children: vec![],
contents,
@ -120,7 +118,6 @@ impl History {
&mut self,
new_id: Id,
new_actor: PublicKey,
new_author: Option<Oid>,
new_resource: Oid,
new_contents: Contents,
) where
@ -131,7 +128,6 @@ impl History {
let new_entry = Entry::new(
new_id,
new_actor,
new_author,
new_resource,
std::iter::empty::<git2::Oid>(),
new_contents,

View File

@ -45,9 +45,6 @@ pub struct Entry {
pub(super) id: EntryId,
/// The actor that authored this entry.
pub(super) actor: PublicKey,
/// The content-address for this entry's author.
/// TODO: This shouldn't be here?
pub(super) author: Option<Oid>,
/// The content-address for the resource this entry lives under.
pub(super) resource: Oid,
/// The child entries for this entry.
@ -60,7 +57,6 @@ impl Entry {
pub fn new<Id1, Id2, ChildIds>(
id: Id1,
actor: PublicKey,
author: Option<Oid>,
resource: Oid,
children: ChildIds,
contents: Contents,
@ -73,7 +69,6 @@ impl Entry {
Self {
id: id.into(),
actor,
author,
resource,
children: children.into_iter().map(|id| id.into()).collect(),
contents,
@ -95,11 +90,6 @@ impl Entry {
&self.actor
}
/// The `Oid` of the author that made this change.
pub fn author(&self) -> Option<&Oid> {
self.author.as_ref()
}
/// The contents of this change
pub fn contents(&self) -> &Contents {
&self.contents

View File

@ -8,17 +8,10 @@ use git_ext::Oid;
/// An [`Identity`] represents a content addressed identity
/// (i.e. expected to be stored in a git backend).
///
/// It should have:
/// * A delegate system
/// * A content addressable identifier
/// * A unique, stable identifier
/// It should have a unique, stable, content addressable identifier.
pub trait Identity {
type Identifier;
/// Confirm that the given [`crypto::PublicKey`] is a delegate for
/// the identity.
fn is_delegate(&self, delegation: &crypto::PublicKey) -> bool;
/// Provide the content address for the given identity. This is
/// expected to be the latest address for the identity at the time
/// of use.

View File

@ -61,11 +61,11 @@
//! automerge document and deserialize into an application defined
//! object.
//!
//! This traversal is also the point at which the [`Entry::author`]
//! This traversal is also the point at which the [`Entry::actor`]
//! and [`Entry::resource`] can be retrieved to apply any kind of
//! filtering logic. For example, a specific `author`'s change may be
//! filtering logic. For example, a specific `actor`'s change may be
//! egregious, spouting terrible libel about Radicle. It is at this
//! point that the `author`'s change can be filtered out from the
//! point that the `actor`'s change can be filtered out from the
//! final product of the traversal.
//!
//! [automerge]: https://automerge.org
@ -132,7 +132,6 @@ where
CreateError = git::change::error::Create,
LoadError = git::change::error::Load,
ObjectId = git_ext::Oid,
Author = git_ext::Oid,
Resource = git_ext::Oid,
Signatures = Signature,
>,

View File

@ -8,9 +8,7 @@ use crate::Store;
use super::*;
/// The metadata required for creating a new [`CollaborativeObject`].
pub struct Create<Author> {
/// The identity of the author for this object's first change.
pub author: Option<Author>,
pub struct Create {
/// The type of history that will be used for this object.
pub history_type: String,
/// The CRDT history to initialize this object with.
@ -21,7 +19,7 @@ pub struct Create<Author> {
pub message: String,
}
impl<Author> Create<Author> {
impl Create {
fn create_spec(&self) -> change::Create<git_ext::Oid> {
change::Create {
typename: self.typename.clone(),
@ -51,46 +49,31 @@ impl<Author> Create<Author> {
///
/// The `args` are the metadata for this [`CollaborativeObject`]. See
/// [`Create`] for further information.
pub fn create<S, G, Author, Resource>(
pub fn create<S, G, Resource>(
storage: &S,
signer: &G,
resource: &Resource,
identifier: &S::Identifier,
args: Create<Author>,
args: Create,
) -> Result<CollaborativeObject, error::Create>
where
S: Store,
G: crypto::Signer,
Author: Identity,
Author::Identifier: Clone + PartialEq,
Resource: Identity,
{
let Create {
author,
ref contents,
ref typename,
..
} = &args;
let content = match author {
None => None,
Some(author) => {
if !author.is_delegate(signer.public_key()) {
return Err(error::Create::SignerIsNotAuthor);
} else {
Some(author.content_id())
}
}
};
let init_change = storage
.create(content, resource.content_id(), signer, args.create_spec())
.create(resource.content_id(), signer, args.create_spec())
.map_err(error::Create::from)?;
let history = History::new_from_root(
*init_change.id(),
init_change.signature.key,
content,
resource.content_id(),
contents.clone(),
);

View File

@ -11,9 +11,7 @@ use crate::{
use super::error;
/// The data required to update an object
pub struct Update<Author> {
/// The identity of the author for the update of this object.
pub author: Option<Author>,
pub struct Update {
/// The type of history that will be used for this object.
pub history_type: String,
/// The CRDT changes to add to the object.
@ -44,22 +42,19 @@ pub struct Update<Author> {
///
/// The `args` are the metadata for this [`CollaborativeObject`]
/// udpate. See [`Update`] for further information.
pub fn update<S, G, Resource, Author>(
pub fn update<S, G, Resource>(
storage: &S,
signer: &G,
resource: &Resource,
identifier: &S::Identifier,
args: Update<Author>,
args: Update,
) -> Result<CollaborativeObject, error::Update>
where
S: Store,
G: crypto::Signer,
Author: Identity,
Author::Identifier: Clone + PartialEq,
Resource: Identity,
{
let Update {
author,
ref typename,
object_id,
history_type,
@ -67,18 +62,6 @@ where
message,
} = args;
let author = match author {
None => None,
Some(author) => {
// TODO: Remove?
if !author.is_delegate(signer.public_key()) {
return Err(error::Update::SignerIsNotAuthor);
} else {
Some(author.content_id())
}
}
};
let existing_refs = storage
.objects(typename, &object_id)
.map_err(|err| error::Update::Refs { err: Box::new(err) })?;
@ -88,7 +71,6 @@ where
.ok_or(error::Update::NoSuchObject)?;
let change = storage.create(
author,
resource.content_id(),
signer,
change::Create {
@ -99,13 +81,9 @@ where
message,
},
)?;
object.history.extend(
change.id,
change.signature.key,
author,
change.resource,
changes,
);
object
.history
.extend(change.id, change.signature.key, change.resource, changes);
storage
.update(identifier, typename, &object_id, &change)
.map_err(|err| error::Update::Refs { err: Box::new(err) })?;

View File

@ -53,52 +53,14 @@ impl Person {
})
}
pub fn key(&self) -> crypto::PublicKey {
self.payload.key
}
pub fn name(&self) -> &Name {
&self.payload.name
}
pub fn find_by_oid(
repo: &git2::Repository,
id: Oid,
) -> Result<Option<Person>, storage::error::Identity> {
match repo.find_commit(id.into()) {
Ok(commit) => from_commit(repo, commit),
Err(err) if err.code() == git2::ErrorCode::NotFound => Ok(None),
Err(err) => Err(err.into()),
}
}
}
fn from_commit(
repo: &git2::Repository,
commit: git2::Commit,
) -> Result<Option<Person>, storage::error::Identity> {
let tree = commit.tree()?;
let entry = tree
.get_name("identity")
.ok_or_else(|| storage::error::Identity::NotFound(tree.id().into()))?;
let blob = match entry.to_object(repo)?.into_blob() {
Ok(blob) => blob,
Err(other) => return Err(storage::error::Identity::NotBlob(other.kind())),
};
let payload = serde_json::de::from_slice(blob.content())?;
Ok(Some(Person {
payload,
content_id: commit.id().into(),
}))
}
impl Identity for Person {
type Identifier = Urn;
fn is_delegate(&self, delegation: &crypto::PublicKey) -> bool {
self.key() == *delegation
}
fn content_id(&self) -> Oid {
self.content_id
}

View File

@ -70,56 +70,14 @@ impl Project {
})
}
pub fn delegates(&self) -> &BTreeSet<crypto::PublicKey> {
&self.payload.delegates
}
pub fn delegate_check(&self, person: &test::Person) -> bool {
self.payload.delegates.contains(&person.key())
}
pub fn name(&self) -> &Name {
&self.payload.name
}
pub fn find_by_oid(
repo: &git2::Repository,
id: Oid,
) -> Result<Option<Self>, storage::error::Identity> {
match repo.find_commit(id.into()) {
Ok(commit) => from_commit(repo, commit),
Err(err) if err.code() == git2::ErrorCode::NotFound => Ok(None),
Err(err) => Err(err.into()),
}
}
}
fn from_commit(
repo: &git2::Repository,
commit: git2::Commit,
) -> Result<Option<Project>, storage::error::Identity> {
let tree = commit.tree()?;
let entry = tree
.get_name("identity")
.ok_or_else(|| storage::error::Identity::NotFound(tree.id().into()))?;
let blob = match entry.to_object(repo)?.into_blob() {
Ok(blob) => blob,
Err(other) => return Err(storage::error::Identity::NotBlob(other.kind())),
};
let payload = serde_json::de::from_slice(blob.content())?;
Ok(Some(Project {
payload,
content_id: commit.id().into(),
}))
}
impl Identity for RemoteProject {
type Identifier = Urn;
fn is_delegate(&self, delegation: &crypto::PublicKey) -> bool {
self.project.delegates().contains(delegation)
}
fn content_id(&self) -> Oid {
self.project.content_id
}

View File

@ -21,10 +21,6 @@ pub mod error {
Json(#[from] serde_json::Error),
#[error(transparent)]
Git(#[from] git2::Error),
#[error("'identity' was not a blob, found '{0:?}'")]
NotBlob(Option<git2::ObjectType>),
#[error("could not find 'identity' in the tree '{0}'")]
NotFound(git_ext::Oid),
}
#[derive(Debug, Error)]
@ -67,31 +63,29 @@ impl change::Storage for Storage {
type LoadError = <git2::Repository as change::Storage>::LoadError;
type ObjectId = <git2::Repository as change::Storage>::ObjectId;
type Author = <git2::Repository as change::Storage>::Author;
type Resource = <git2::Repository as change::Storage>::Resource;
type Signatures = <git2::Repository as change::Storage>::Signatures;
fn create<Signer>(
&self,
author: Option<Self::Author>,
authority: Self::Resource,
signer: &Signer,
spec: change::Create<Self::ObjectId>,
) -> Result<
change::store::Change<Self::Author, Self::Resource, Self::ObjectId, Self::Signatures>,
change::store::Change<Self::Resource, Self::ObjectId, Self::Signatures>,
Self::CreateError,
>
where
Signer: crypto::Signer,
{
self.as_raw().create(author, authority, signer, spec)
self.as_raw().create(authority, signer, spec)
}
fn load(
&self,
id: Self::ObjectId,
) -> Result<
change::store::Change<Self::Author, Self::Resource, Self::ObjectId, Self::Signatures>,
change::store::Change<Self::Resource, Self::ObjectId, Self::Signatures>,
Self::LoadError,
> {
self.as_raw().load(id)

View File

@ -19,7 +19,7 @@ fn roundtrip() {
let proj = test::Project::new(&storage, "discworld", *signer.public_key()).unwrap();
let proj = test::RemoteProject {
project: proj,
person: terry.clone(),
person: terry,
};
let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
let cob = create(
@ -28,7 +28,6 @@ fn roundtrip() {
&proj,
&proj.identifier(),
Create {
author: Some(terry),
history_type: "test".to_string(),
contents: Vec::new(),
typename: typename.clone(),
@ -52,7 +51,7 @@ fn list_cobs() {
let proj = test::Project::new(&storage, "discworld", *signer.public_key()).unwrap();
let proj = test::RemoteProject {
project: proj,
person: terry.clone(),
person: terry,
};
let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
let issue_1 = create(
@ -61,7 +60,6 @@ fn list_cobs() {
&proj,
&proj.identifier(),
Create {
author: Some(terry.clone()),
history_type: "test".to_string(),
contents: b"issue 1".to_vec(),
typename: typename.clone(),
@ -76,7 +74,6 @@ fn list_cobs() {
&proj,
&proj.identifier(),
Create {
author: Some(terry),
history_type: "test".to_string(),
contents: b"issue 2".to_vec(),
typename: typename.clone(),
@ -102,7 +99,7 @@ fn update_cob() {
let proj = test::Project::new(&storage, "discworld", *signer.public_key()).unwrap();
let proj = test::RemoteProject {
project: proj,
person: terry.clone(),
person: terry,
};
let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
let cob = create(
@ -111,7 +108,6 @@ fn update_cob() {
&proj,
&proj.identifier(),
Create {
author: Some(terry.clone()),
history_type: "test".to_string(),
contents: Vec::new(),
typename: typename.clone(),
@ -130,7 +126,6 @@ fn update_cob() {
&proj,
&proj.identifier(),
Update {
author: Some(terry),
changes: b"issue 1".to_vec(),
history_type: "test".to_string(),
object_id: *cob.id(),
@ -158,11 +153,11 @@ fn traverse_cobs() {
let proj = test::Project::new(&storage, "discworld", *terry_signer.public_key()).unwrap();
let terry_proj = test::RemoteProject {
project: proj.clone(),
person: terry.clone(),
person: terry,
};
let neil_proj = test::RemoteProject {
project: proj,
person: neil.clone(),
person: neil,
};
let typename = "xyz.rad.issue".parse::<TypeName>().unwrap();
let cob = create(
@ -171,7 +166,6 @@ fn traverse_cobs() {
&terry_proj,
&terry_proj.identifier(),
Create {
author: Some(terry),
contents: b"issue 1".to_vec(),
history_type: "test".to_string(),
typename: typename.clone(),
@ -194,7 +188,6 @@ fn traverse_cobs() {
&neil_proj,
&neil_proj.identifier(),
Update {
author: Some(neil),
changes: b"issue 2".to_vec(),
history_type: "test".to_string(),
object_id: *cob.id(),
@ -206,16 +199,8 @@ fn traverse_cobs() {
// traverse over the history and filter by changes that were only authorized by terry
let contents = updated.history().traverse(Vec::new(), |mut acc, entry| {
let author = match entry.author() {
Some(author) => test::Person::find_by_oid(storage.as_raw(), *author).unwrap(),
None => None,
};
let project = test::Project::find_by_oid(storage.as_raw(), entry.resource()).unwrap();
if let (Some(author), Some(project)) = (author, project) {
if project.delegate_check(&author) {
acc.push(entry.contents().to_vec())
}
if entry.actor() == terry_signer.public_key() {
acc.push(entry.contents().to_vec());
}
ControlFlow::Continue(acc)
});

View File

@ -3,20 +3,14 @@
// This file is part of radicle-link, distributed under the GPLv3 with Radicle
// Linking Exception. For full terms see the included LICENSE file.
mod author_commit {
super::oid_trailer! {AuthorCommitTrailer, "Rad-Author"}
}
mod resource_identity {
super::oid_trailer! {ResourceCommitTrailer, "Rad-Resource"}
}
pub mod error {
pub use super::author_commit::Error as InvalidAuthorTrailer;
pub use super::resource_identity::Error as InvalidResourceTrailer;
}
pub use author_commit::AuthorCommitTrailer;
pub use resource_identity::ResourceCommitTrailer;
/// A macro for generating boilerplate From and TryFrom impls for trailers which

View File

@ -13,48 +13,7 @@ pub use common::*;
use radicle_cob as cob;
use radicle_git_ext::Oid;
use crate::{
identity::{project::Identity, Did},
node::NodeId,
storage::git::Repository,
};
/// The `Author` of a [`create`] or [`update`].
///
/// **Note**: `Author` implements [`identity::Identity`], but since it
/// is not content-addressed, the [`identity::Identity::content_id`]
/// returns [`git2::Oid::zero`]. This means that if the `author` is
/// set in the updates the history entries for those changes will
/// contain the zero `Oid` for the `author` field.
pub struct Author {
did: Did,
}
impl From<Did> for Author {
fn from(did: Did) -> Self {
Self { did }
}
}
impl From<NodeId> for Author {
fn from(node_id: NodeId) -> Self {
Self {
did: Did::from(node_id),
}
}
}
impl identity::Identity for Author {
type Identifier = String;
fn is_delegate(&self, delegation: &crypto::PublicKey) -> bool {
*self.did == *delegation
}
fn content_id(&self) -> Oid {
git2::Oid::zero().into()
}
}
use crate::{identity::project::Identity, storage::git::Repository};
/// Create a new [`CollaborativeObject`].
///
@ -62,8 +21,7 @@ impl identity::Identity for Author {
/// stored under.
///
/// The `signer` is used to cryptographically sign the changes made
/// for this update. **Note** that the public key for the signer must
/// match the key of the `Author` -- if it is set.
/// for this update.
///
/// The `project` is used to store its content-address in the history
/// of changes for the collaborative object.
@ -74,7 +32,7 @@ pub fn create<G>(
repository: &Repository,
signer: &G,
project: &Identity<Oid>,
args: Create<Author>,
args: Create,
) -> Result<CollaborativeObject, error::Create>
where
G: crypto::Signer,
@ -118,8 +76,7 @@ pub fn list(
/// stored under.
///
/// The `signer` is used to cryptographically sign the changes made
/// for this update. **Note** that the public key for the signer must
/// match the key of the `Author` -- if it is set.
/// for this update.
///
/// The `project` is used to store its content-address in the history
/// of changes for the collaborative object.
@ -130,7 +87,7 @@ pub fn update<G>(
repository: &Repository,
signer: &G,
project: &Identity<Oid>,
args: Update<Author>,
args: Update,
) -> Result<CollaborativeObject, error::Update>
where
G: crypto::Signer,

View File

@ -103,7 +103,6 @@ where
signer,
&self.project,
Update {
author: Some(cob::Author::from(*signer.public_key())),
object_id,
history_type: HISTORY_TYPE.to_owned(),
typename: T::type_name().clone(),
@ -127,7 +126,6 @@ where
signer,
&self.project,
Create {
author: Some(cob::Author::from(*signer.public_key())),
history_type: HISTORY_TYPE.to_owned(),
typename: T::type_name().clone(),
message: message.to_owned(),

View File

@ -406,10 +406,6 @@ pub struct Identity<I> {
impl radicle_cob::identity::Identity for Identity<Oid> {
type Identifier = Oid;
fn is_delegate(&self, delegation: &crypto::PublicKey) -> bool {
self.doc.delegates.iter().any(|d| d.matches(delegation))
}
fn content_id(&self) -> Oid {
self.current
}

View File

@ -681,13 +681,11 @@ impl change::Storage for Repository {
type LoadError = <git2::Repository as change::Storage>::LoadError;
type ObjectId = <git2::Repository as change::Storage>::ObjectId;
type Author = <git2::Repository as change::Storage>::Author;
type Resource = <git2::Repository as change::Storage>::Resource;
type Signatures = <git2::Repository as change::Storage>::Signatures;
fn create<Signer>(
&self,
author: Option<Self::Author>,
authority: Self::Resource,
signer: &Signer,
spec: change::Create<Self::ObjectId>,
@ -695,7 +693,7 @@ impl change::Storage for Repository {
where
Signer: crypto::Signer,
{
self.backend.create(author, authority, signer, spec)
self.backend.create(authority, signer, spec)
}
fn load(&self, id: Self::ObjectId) -> Result<cob::Change, Self::LoadError> {