use crate::errors::{
JUNO_STORAGE_ERROR_CANNOT_COMMIT_BATCH, JUNO_STORAGE_ERROR_CANNOT_COMMIT_INVALID_COLLECTION,
JUNO_STORAGE_ERROR_UPLOAD_NOT_ALLOWED, JUNO_STORAGE_ERROR_UPLOAD_PATH_COLLECTION_PREFIX,
};
use crate::runtime::increment_and_assert_rate;
use crate::strategies::{StorageAssertionsStrategy, StorageStateStrategy};
use crate::types::config::StorageConfig;
use crate::types::interface::{CommitBatch, InitAssetKey};
use crate::types::state::FullPath;
use crate::types::store::{Asset, AssetAssertUpload, Batch};
use crate::well_known::assert::assert_not_well_known_asset;
use candid::Principal;
use junobuild_collections::assert::collection::is_system_collection;
use junobuild_collections::constants::assets::COLLECTION_ASSET_KEY;
use junobuild_collections::constants::core::SYS_COLLECTION_PREFIX;
use junobuild_collections::types::core::CollectionKey;
use junobuild_collections::types::rules::Rule;
use junobuild_shared::assert::{assert_description_length, assert_max_memory_size};
use junobuild_shared::types::state::AccessKeys;
use junobuild_shared::utils::principal_not_equal;
pub fn assert_create_batch(
caller: Principal,
controllers: &AccessKeys,
config: &StorageConfig,
init: &InitAssetKey,
assertions: &impl StorageAssertionsStrategy,
storage_state: &impl StorageStateStrategy,
) -> Result<(), String> {
assert_memory_size(config)?;
assert_key(
caller,
&init.full_path,
&init.description,
&init.collection,
assertions,
controllers,
)?;
assert_description_length(&init.description)?;
let rule = storage_state.get_rule(&init.collection)?;
increment_and_assert_rate(&init.collection, &rule.rate_config)?;
Ok(())
}
pub fn assert_create_chunk(
caller: Principal,
config: &StorageConfig,
batch: &Batch,
) -> Result<(), String> {
if principal_not_equal(caller, batch.key.owner) {
return Err("Bach initializer does not match chunk uploader.".to_string());
}
assert_memory_size(config)?;
Ok(())
}
pub fn assert_commit_batch(
caller: Principal,
controllers: &AccessKeys,
batch: &Batch,
assertions: &impl StorageAssertionsStrategy,
storage_state: &impl StorageStateStrategy,
) -> Result<Rule, String> {
if principal_not_equal(caller, batch.key.owner) {
return Err(JUNO_STORAGE_ERROR_CANNOT_COMMIT_BATCH.to_string());
}
assert_key(
caller,
&batch.key.full_path,
&batch.key.description,
&batch.key.collection,
assertions,
controllers,
)?;
let rule = storage_state.get_rule(&batch.key.collection)?;
increment_and_assert_rate(&batch.key.collection, &rule.rate_config)?;
Ok(rule)
}
pub fn assert_commit_chunks_new_asset(
caller: Principal,
collection: &CollectionKey,
controllers: &AccessKeys,
config: &StorageConfig,
rule: &Rule,
assertions: &impl StorageAssertionsStrategy,
) -> Result<(), String> {
if !assertions.assert_create_permission(&rule.write, caller, collection, controllers) {
return Err(JUNO_STORAGE_ERROR_CANNOT_COMMIT_BATCH.to_string());
}
assert_memory_size(config)?;
Ok(())
}
pub fn assert_commit_chunks_update(
caller: Principal,
controllers: &AccessKeys,
config: &StorageConfig,
batch: &Batch,
rule: &Rule,
current: &Asset,
assertions: &impl StorageAssertionsStrategy,
) -> Result<(), String> {
if batch.key.collection != current.key.collection {
return Err(JUNO_STORAGE_ERROR_CANNOT_COMMIT_INVALID_COLLECTION.to_string());
}
if !assertions.assert_update_permission(
&rule.write,
current.key.owner,
caller,
&batch.key.collection,
controllers,
) {
return Err(JUNO_STORAGE_ERROR_CANNOT_COMMIT_BATCH.to_string());
}
assert_memory_size(config)?;
Ok(())
}
pub fn assert_commit_chunks(
caller: Principal,
controllers: &AccessKeys,
commit_batch: &CommitBatch,
batch: &Batch,
current: &Option<Asset>,
rule: &Rule,
assertions: &impl StorageAssertionsStrategy,
) -> Result<(), String> {
assertions.invoke_assert_upload_asset(
&caller,
&AssetAssertUpload {
current: current.clone(),
batch: batch.clone(),
commit_batch: commit_batch.clone(),
},
)?;
assertions.increment_and_assert_storage_usage(
&caller,
controllers,
&batch.key.collection,
rule.max_changes_per_user,
)?;
Ok(())
}
fn assert_memory_size(config: &StorageConfig) -> Result<(), String> {
assert_max_memory_size(&config.max_memory_size)
}
fn assert_key(
caller: Principal,
full_path: &FullPath,
description: &Option<String>,
collection: &CollectionKey,
assertions: &impl StorageAssertionsStrategy,
controllers: &AccessKeys,
) -> Result<(), String> {
assert_not_well_known_asset(full_path)?;
let dapp_collection = COLLECTION_ASSET_KEY;
if is_system_collection(collection) {
let allowed = if collection.clone() == *dapp_collection {
assertions.assert_write_on_dapp_collection(caller, controllers)
} else {
assertions.assert_write_on_system_collection(caller, collection, controllers)
};
if !allowed {
return Err(JUNO_STORAGE_ERROR_UPLOAD_NOT_ALLOWED.to_string());
}
}
let collection_path = collection
.strip_prefix(SYS_COLLECTION_PREFIX)
.unwrap_or(collection);
if collection.clone() != *dapp_collection
&& !full_path.starts_with(&["/", collection_path, "/"].join(""))
{
return Err(JUNO_STORAGE_ERROR_UPLOAD_PATH_COLLECTION_PREFIX.to_string());
}
assertions.assert_key(full_path, description, collection)?;
Ok(())
}