radicle_cob/object/collaboration/
create.rs

1// Copyright © 2022 The Radicle Link Contributors
2
3use nonempty::NonEmpty;
4use radicle_crypto::PublicKey;
5
6use crate::Embed;
7use crate::Evaluate;
8use crate::Store;
9
10use super::*;
11
12/// The metadata required for creating a new [`CollaborativeObject`].
13pub struct Create {
14    /// The CRDT history to initialize this object with.
15    pub contents: NonEmpty<Vec<u8>>,
16    /// The typename for this object.
17    pub type_name: TypeName,
18    /// The message to add when creating this object.
19    pub message: String,
20    /// Embedded content.
21    pub embeds: Vec<Embed<Oid>>,
22    /// COB version.
23    pub version: Version,
24}
25
26impl Create {
27    fn template(self) -> change::Template<git_ext::Oid> {
28        change::Template {
29            type_name: self.type_name,
30            tips: Vec::new(),
31            message: self.message,
32            embeds: self.embeds,
33            contents: self.contents,
34        }
35    }
36}
37
38/// Create a new [`CollaborativeObject`].
39///
40/// The `storage` is the backing storage for storing
41/// [`crate::Entry`]s at content-addressable locations. Please see
42/// [`Store`] for further information.
43///
44/// The `signer` is expected to be a cryptographic signing key. This
45/// ensures that the objects origin is cryptographically verifiable.
46///
47/// The `resource` is the parent of this object, for example a
48/// software project. Its content-address is stored in the object's
49/// history.
50///
51/// The `identifier` is a unqiue id that is passed through to the
52/// [`crate::object::Storage`].
53///
54/// The `args` are the metadata for this [`CollaborativeObject`]. See
55/// [`Create`] for further information.
56pub fn create<T, S, G>(
57    storage: &S,
58    signer: &G,
59    resource: Option<Oid>,
60    related: Vec<Oid>,
61    identifier: &PublicKey,
62    args: Create,
63) -> Result<CollaborativeObject<T>, error::Create>
64where
65    T: Evaluate<S>,
66    S: Store,
67    G: crypto::Signer,
68{
69    let type_name = args.type_name.clone();
70    let version = args.version;
71    let init_change = storage
72        .store(resource, related, signer, args.template())
73        .map_err(error::Create::from)?;
74    let object_id = init_change.id().into();
75    let object = T::init(&init_change, storage).map_err(error::Create::evaluate)?;
76
77    storage
78        .update(identifier, &type_name, &object_id, &object_id)
79        .map_err(|err| error::Create::Refs { err: Box::new(err) })?;
80
81    let history = History::new_from_root(init_change);
82
83    Ok(CollaborativeObject {
84        manifest: Manifest::new(type_name, version),
85        history,
86        object,
87        id: object_id,
88    })
89}