#![allow(dead_code)]
use knot_cob::{Approved, CobHome, CobStore, Materialized, Record, WriteContext};
use knot_cobs::{
CollaboratorsChange, Creation, Editing, Erasure, Grant, Manifest, SocialBody, SocialChange,
SocialCob, Ticket,
};
use knot_git::Repo;
use knot_record::ticket::TicketState;
use knot_runtime::Signer;
use knot_types::{
AccountDid, Blocked, CobId, ContributionPermission, ContributionPolicy, RecordAddress,
RecordBody, RecordCid, RecordCollection, RecordRkey, RepoDid, RepoRole, SubjectNumber,
UnixSeconds,
};
fn owner_context<'a>(author: &'a AccountDid, repo: &'a RepoDid) -> WriteContext<'a> {
WriteContext::new(
author,
repo,
ContributionPermission::new(Blocked::No, RepoRole::Owner, ContributionPolicy::Anyone),
)
}
fn at(seconds: i64) -> UnixSeconds {
UnixSeconds::new(seconds)
}
pub fn record(collection: &str, text: &str) -> RecordBody {
RecordBody::new(
serde_ipld_dagcbor::to_vec(&serde_json::json!({ "$type": collection, "text": text }))
.unwrap(),
)
.unwrap()
}
pub struct Cobs<'a> {
pub repo: &'a Repo,
pub did: &'a RepoDid,
pub signer: &'a dyn Signer,
}
impl Cobs<'_> {
fn store(&self) -> CobStore<'_> {
CobStore::new(self.repo)
}
pub fn open<B: SocialBody>(
&self,
key: &str,
author: &AccountDid,
number: u32,
body: B,
text: &str,
seconds: i64,
) -> (CobId, RecordCid) {
let record = record(B::COLLECTION, text);
let produces = record.cid();
let address = RecordAddress::new(
RecordCollection::new(B::COLLECTION).unwrap(),
RecordRkey::new(key).unwrap(),
);
let change = SocialChange::Open {
creation: Creation {
address,
author: author.clone(),
number: SubjectNumber::new(number).unwrap(),
parent: None,
created_at: at(seconds),
produces,
},
body,
};
let object = self.create(change, author, Record::version(record), seconds);
(object, produces)
}
fn create<B: SocialBody>(
&self,
change: SocialChange<B>,
author: &AccountDid,
record: Record,
seconds: i64,
) -> CobId {
let cx = owner_context(author, self.did);
let approved = Approved::signed_by(&cx, Materialized { change, record }).unwrap();
self.store()
.create_approved::<SocialCob<B>>(
&CobHome::from(self.did),
&approved,
self.signer,
at(seconds),
)
.unwrap()
.object
}
pub fn open_ticket(&self, key: &str, author: &AccountDid, text: &str) -> (CobId, RecordCid) {
let body = Ticket {
state: TicketState::Open,
tangled_labels: None,
assignees: None,
};
self.open(key, author, 1, body, text, 10)
}
pub fn edit_ticket(
&self,
object: CobId,
author: &AccountDid,
from: RecordCid,
text: &str,
seconds: i64,
) -> RecordCid {
let record = record(<Ticket as SocialBody>::COLLECTION, text);
let produces = record.cid();
let change = SocialChange::Edit {
editing: Editing {
author: author.clone(),
from,
produces,
edited_at: at(seconds),
},
body: Ticket {
state: TicketState::Open,
tangled_labels: None,
assignees: None,
},
};
self.append::<Ticket>(object, author, change, Record::version(record), seconds);
produces
}
pub fn erase<B: SocialBody>(
&self,
object: CobId,
author: &AccountDid,
from: RecordCid,
seconds: i64,
) {
let change = SocialChange::Erase {
erasure: Erasure {
author: author.clone(),
from,
erased_at: at(seconds),
},
};
self.append::<B>(object, author, change, Record::Tombstone, seconds);
}
fn append<B: SocialBody>(
&self,
object: CobId,
author: &AccountDid,
change: SocialChange<B>,
record: Record,
seconds: i64,
) {
let cx = owner_context(author, self.did);
let approved = Approved::signed_by(&cx, Materialized { change, record }).unwrap();
self.store()
.append_approved::<SocialCob<B>>(
&CobHome::from(self.did),
object,
&approved,
self.signer,
at(seconds),
)
.unwrap();
}
pub fn open_manifest(&self, owner: &AccountDid, record: RecordBody) {
let produces = record.cid();
let change = SocialChange::Open {
creation: Creation {
address: RecordAddress::new(
knot_record::manifest::manifest_collection(),
RecordRkey::new(knot_record::manifest::MANIFEST_RKEY).unwrap(),
),
author: owner.clone(),
number: SubjectNumber::new(1).unwrap(),
parent: None,
created_at: at(5),
produces,
},
body: Manifest,
};
self.create(change, owner, Record::version(record), 5);
}
pub fn add_collaborator(&self, subject: &AccountDid, added_by: &AccountDid, seconds: i64) {
self.store()
.create(
&CobHome::from(self.did),
&CollaboratorsChange::Add(Grant {
subject: subject.clone(),
added_by: added_by.clone(),
created_at: at(seconds),
}),
self.signer,
at(seconds),
)
.unwrap();
}
}