use crate::access_container;
use crate::client::AuthClient;
use crate::AuthError;
use safe_core::btree_map;
use safe_core::{app_container_name, Client, MDataInfo, DIR_TAG};
use safe_nd::{
MDataAction, MDataKind, MDataPermissionSet, MDataSeqEntries, MDataSeqEntryActions, PublicKey,
};
use safe_core::CoreError;
use log::trace;
use safe_nd::{Error as SndError, SeqMutableData};
use std::collections::BTreeMap;
#[cfg(any(test, feature = "testing"))]
pub async fn fetch(client: &AuthClient, app_id: &str) -> Result<Option<MDataInfo>, AuthError> {
let app_cont_name = app_container_name(app_id);
let (_, mut ac_entries) = access_container::fetch_authenticator_entry(client).await?;
Ok(ac_entries.remove(&app_cont_name))
}
pub async fn fetch_or_create(
client: &AuthClient,
app_id: &str,
app_pk: PublicKey,
) -> Result<MDataInfo, AuthError> {
let app_cont_name = app_container_name(app_id);
let (ac_entry_version, mut ac_entries) =
access_container::fetch_authenticator_entry(client).await?;
match ac_entries.remove(&app_cont_name) {
Some(mdata_info) => {
let ps = MDataPermissionSet::new()
.allow(MDataAction::Read)
.allow(MDataAction::Insert)
.allow(MDataAction::Update)
.allow(MDataAction::Delete)
.allow(MDataAction::ManagePermissions);
let version = client.get_mdata_version(*mdata_info.address()).await?;
client
.set_mdata_user_permissions(*mdata_info.address(), app_pk, ps, version + 1)
.await?;
Ok(mdata_info)
}
None => {
let md_info = create(&client, app_pk).await?;
let _ = ac_entries.insert(app_cont_name, md_info.clone());
access_container::put_authenticator_entry(&client, &ac_entries, ac_entry_version + 1)
.await?;
Ok(md_info)
}
}
}
pub async fn remove(client: AuthClient, app_id: &str) -> Result<bool, AuthError> {
let c2 = client.clone();
let app_cont_name = app_container_name(app_id);
let (ac_entry_version, mut ac_entries) =
access_container::fetch_authenticator_entry(&client).await?;
match ac_entries.remove(&app_cont_name) {
None => {
Ok(false)
}
Some(mdata_info) => {
let c3 = c2.clone();
let entries = c2
.list_seq_mdata_entries(mdata_info.name(), mdata_info.type_tag())
.await?;
let actions = entries
.iter()
.fold(MDataSeqEntryActions::new(), |actions, (entry_name, val)| {
actions.del(entry_name.clone(), val.version + 1)
});
c3.mutate_seq_mdata_entries(mdata_info.name(), mdata_info.type_tag(), actions)
.await?;
access_container::put_authenticator_entry(&client, &ac_entries, ac_entry_version + 1)
.await?;
Ok(true)
}
}
}
async fn create_directory(
client: &impl Client,
dir: &MDataInfo,
contents: MDataSeqEntries,
perms: BTreeMap<PublicKey, MDataPermissionSet>,
) -> Result<(), AuthError> {
let pub_key = client.owner_key().await;
let dir_md =
SeqMutableData::new_with_data(dir.name(), dir.type_tag(), contents, perms, pub_key);
trace!("Creating new directory: {:?}", dir);
client
.put_seq_mutable_data(dir_md)
.await
.or_else(move |err| {
println!("====Error: {:?}", err);
match err {
CoreError::DataError(SndError::DataExists) => Ok(()),
e => Err(e),
}
})
.map_err(AuthError::from)
}
async fn create(client: &AuthClient, app_pk: PublicKey) -> Result<MDataInfo, AuthError> {
let dir = MDataInfo::random_private(MDataKind::Seq, DIR_TAG).map_err(AuthError::from)?;
create_directory(
client,
&dir,
btree_map![],
btree_map![app_pk => MDataPermissionSet::new()
.allow(MDataAction::Read)
.allow(MDataAction::Insert)
.allow(MDataAction::Update)
.allow(MDataAction::Delete)
.allow(MDataAction::ManagePermissions)],
)
.await?;
Ok(dir)
}