1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645 |
- // Ensure we're `no_std` when compiling for Wasm.
- #![cfg_attr(not(feature = "std"), no_std)]
- #![recursion_limit = "256"]
- use codec::{Codec, Decode, Encode};
- use rstd::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
- use rstd::prelude::*;
- use runtime_primitives::traits::{MaybeSerializeDeserialize, Member, One, SimpleArithmetic, Zero};
- use srml_support::{
- decl_module, decl_storage, dispatch, ensure, traits::Get, Parameter, StorageDoubleMap,
- };
- use system::ensure_signed;
- #[cfg(feature = "std")]
- pub use serde::{Deserialize, Serialize};
- mod errors;
- mod mock;
- mod operations;
- mod permissions;
- mod schema;
- mod tests;
- use core::fmt::Debug;
- pub use errors::*;
- pub use operations::*;
- pub use permissions::*;
- pub use schema::*;
- type MaxNumber = u32;
- /// Type, representing vector of vectors of all referenced entitity id`s
- type EntitiesRcVec<T> = Vec<Vec<<T as Trait>::EntityId>>;
- pub trait Trait: system::Trait + ActorAuthenticator + Debug + Clone {
- /// Nonce type is used to avoid data race update conditions, when performing property value vector operations
- type Nonce: Parameter
- + Member
- + SimpleArithmetic
- + Codec
- + Default
- + Copy
- + Clone
- + One
- + Zero
- + MaybeSerializeDeserialize
- + Eq
- + PartialEq
- + Ord
- + From<u32>;
- /// Type of identifier for classes
- type ClassId: Parameter
- + Member
- + SimpleArithmetic
- + Codec
- + Default
- + Copy
- + Clone
- + One
- + Zero
- + MaybeSerializeDeserialize
- + Eq
- + PartialEq
- + Ord;
- /// Type of identifier for entities
- type EntityId: Parameter
- + Member
- + SimpleArithmetic
- + Codec
- + Default
- + Copy
- + Clone
- + One
- + Zero
- + MaybeSerializeDeserialize
- + Eq
- + PartialEq
- + Ord;
- /// Security/configuration constraints
- /// The maximum length of property name
- type PropertyNameConstraint: Get<InputValidationLengthConstraint>;
- /// The maximum length of property description
- type PropertyDescriptionConstraint: Get<InputValidationLengthConstraint>;
- /// Type, representing min & max class name length constraints
- type ClassNameConstraint: Get<InputValidationLengthConstraint>;
- /// Type, representing min & max class description length constraints
- type ClassDescriptionConstraint: Get<InputValidationLengthConstraint>;
- /// The maximum number of classes
- type NumberOfClassesConstraint: Get<MaxNumber>;
- /// The maximum number of maintainers per class constraint
- type NumberOfMaintainersConstraint: Get<MaxNumber>;
- /// The maximum number of curators per group constraint
- type NumberOfCuratorsConstraint: Get<MaxNumber>;
- /// The maximum number of schemas per class constraint
- type NumberOfSchemasConstraint: Get<MaxNumber>;
- /// The maximum number of properties per class constraint
- type NumberOfPropertiesConstraint: Get<MaxNumber>;
- /// The maximum length of vector property value constarint
- type VecMaxLengthConstraint: Get<VecMaxLength>;
- /// The maximum length of text property value constarint
- type TextMaxLengthConstraint: Get<TextMaxLength>;
- /// Entities creation constraint per class
- type EntitiesCreationConstraint: Get<CreationLimit>;
- /// Entities creation constraint per individual
- type IndividualEntitiesCreationConstraint: Get<CreationLimit>;
- }
- /// Length constraint for input validation
- #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
- #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, Debug)]
- pub struct InputValidationLengthConstraint {
- /// Minimum length
- pub min: u16,
- /// Difference between minimum length and max length.
- /// While having max would have been more direct, this
- /// way makes max < min unrepresentable semantically,
- /// which is safer.
- pub max_min_diff: u16,
- }
- impl InputValidationLengthConstraint {
- pub fn new(min: u16, max_min_diff: u16) -> Self {
- Self { min, max_min_diff }
- }
- /// Helper for computing max
- pub fn max(self) -> u16 {
- self.min + self.max_min_diff
- }
- pub fn ensure_valid(
- self,
- len: usize,
- too_short_msg: &'static str,
- too_long_msg: &'static str,
- ) -> Result<(), &'static str> {
- let length = len as u16;
- if length < self.min {
- Err(too_short_msg)
- } else if length > self.max() {
- Err(too_long_msg)
- } else {
- Ok(())
- }
- }
- }
- #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
- #[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
- pub struct Class<T: Trait> {
- /// Permissions for an instance of a Class.
- class_permissions: ClassPermissions<T>,
- /// All properties that have been used on this class across different class schemas.
- /// Unlikely to be more than roughly 20 properties per class, often less.
- /// For Person, think "height", "weight", etc.
- pub properties: Vec<Property<T>>,
- /// All schemas that are available for this class, think v0.0 Person, v.1.0 Person, etc.
- pub schemas: Vec<Schema>,
- pub name: Vec<u8>,
- pub description: Vec<u8>,
- /// The maximum number of entities which can be created.
- maximum_entities_count: CreationLimit,
- /// The current number of entities which exist.
- current_number_of_entities: CreationLimit,
- /// How many entities a given controller may create at most.
- per_controller_entity_creation_limit: CreationLimit,
- }
- impl<T: Trait> Default for Class<T> {
- fn default() -> Self {
- Self {
- class_permissions: ClassPermissions::<T>::default(),
- properties: vec![],
- schemas: vec![],
- name: vec![],
- description: vec![],
- maximum_entities_count: CreationLimit::default(),
- current_number_of_entities: CreationLimit::default(),
- per_controller_entity_creation_limit: CreationLimit::default(),
- }
- }
- }
- impl<T: Trait> Class<T> {
- fn new(
- class_permissions: ClassPermissions<T>,
- name: Vec<u8>,
- description: Vec<u8>,
- maximum_entities_count: CreationLimit,
- per_controller_entity_creation_limit: CreationLimit,
- ) -> Self {
- Self {
- class_permissions,
- properties: vec![],
- schemas: vec![],
- name,
- description,
- maximum_entities_count,
- current_number_of_entities: 0,
- per_controller_entity_creation_limit,
- }
- }
- fn update_schema_status(&mut self, schema_index: SchemaId, schema_status: bool) {
- // Such indexing is safe, when length bounds were previously checked
- self.schemas[schema_index as usize].set_status(schema_status);
- }
- fn set_property_lock_status_at_index(
- &mut self,
- in_class_schema_property_id: PropertyId,
- is_locked: PropertyLockingPolicy,
- ) {
- // Such indexing is safe, when length bounds were previously checked
- self.properties[in_class_schema_property_id as usize].set_locked_for(is_locked)
- }
- fn set_reference_property_same_controller_status(
- &mut self,
- in_class_schema_property_id: PropertyId,
- same_controller: SameController,
- ) {
- // Such indexing is safe, when length bounds were previously checked
- self.properties[in_class_schema_property_id as usize]
- .prop_type
- .set_same_controller_status(same_controller)
- }
- fn increment_entities_count(&mut self) {
- self.current_number_of_entities += 1;
- }
- fn decrement_entities_count(&mut self) {
- self.current_number_of_entities -= 1;
- }
- fn get_permissions_mut(&mut self) -> &mut ClassPermissions<T> {
- &mut self.class_permissions
- }
- fn get_permissions(&self) -> &ClassPermissions<T> {
- &self.class_permissions
- }
- pub fn get_controller_entity_creation_limit(&self) -> CreationLimit {
- self.per_controller_entity_creation_limit
- }
- pub fn get_maximum_entities_count(&self) -> CreationLimit {
- self.maximum_entities_count
- }
- fn is_active_schema(&self, schema_index: SchemaId) -> bool {
- // Such indexing is safe, when length bounds were previously checked
- self.schemas[schema_index as usize].is_active()
- }
- pub fn ensure_schema_id_exists(&self, schema_id: SchemaId) -> dispatch::Result {
- ensure!(
- schema_id < self.schemas.len() as SchemaId,
- ERROR_UNKNOWN_CLASS_SCHEMA_ID
- );
- Ok(())
- }
- pub fn ensure_property_id_exists(
- &self,
- in_class_schema_property_id: PropertyId,
- ) -> dispatch::Result {
- ensure!(
- in_class_schema_property_id < self.properties.len() as PropertyId,
- ERROR_CLASS_PROP_NOT_FOUND
- );
- Ok(())
- }
- pub fn ensure_schema_is_active(&self, schema_id: SchemaId) -> dispatch::Result {
- ensure!(
- self.is_active_schema(schema_id),
- ERROR_CLASS_SCHEMA_NOT_ACTIVE
- );
- Ok(())
- }
- pub fn ensure_schemas_limit_not_reached(&self) -> dispatch::Result {
- ensure!(
- T::NumberOfSchemasConstraint::get() < self.schemas.len() as MaxNumber,
- ERROR_CLASS_SCHEMAS_LIMIT_REACHED
- );
- Ok(())
- }
- pub fn ensure_properties_limit_not_reached(
- &self,
- new_properties: &[Property<T>],
- ) -> dispatch::Result {
- ensure!(
- T::NumberOfPropertiesConstraint::get()
- <= (self.properties.len() + new_properties.len()) as MaxNumber,
- ERROR_CLASS_PROPERTIES_LIMIT_REACHED
- );
- Ok(())
- }
- pub fn ensure_maximum_entities_count_limit_not_reached(&self) -> dispatch::Result {
- ensure!(
- self.current_number_of_entities < self.maximum_entities_count,
- ERROR_MAX_NUMBER_OF_ENTITIES_PER_CLASS_LIMIT_REACHED
- );
- Ok(())
- }
- }
- #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
- #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
- pub struct Entity<T: Trait> {
- /// Permissions for an instance of an Entity.
- pub entity_permission: EntityPermissions<T>,
- /// The class id of this entity.
- pub class_id: T::ClassId,
- /// What schemas under which this entity of a class is available, think
- /// v.2.0 Person schema for John, v3.0 Person schema for John
- /// Unlikely to be more than roughly 20ish, assuming schemas for a given class eventually stableize, or that very old schema are eventually removed.
- pub supported_schemas: BTreeSet<SchemaId>, // indices of schema in corresponding class
- /// Values for properties on class that are used by some schema used by this entity!
- /// Length is no more than Class.properties.
- pub values: BTreeMap<PropertyId, PropertyValue<T>>,
- /// Number of property values referencing current entity
- pub reference_count: u32,
- }
- impl<T: Trait> Default for Entity<T> {
- fn default() -> Self {
- Self {
- entity_permission: EntityPermissions::<T>::default(),
- class_id: T::ClassId::default(),
- supported_schemas: BTreeSet::new(),
- values: BTreeMap::new(),
- reference_count: 0,
- }
- }
- }
- impl<T: Trait> Entity<T> {
- fn new(
- controller: EntityController<T>,
- class_id: T::ClassId,
- supported_schemas: BTreeSet<SchemaId>,
- values: BTreeMap<PropertyId, PropertyValue<T>>,
- ) -> Self {
- Self {
- entity_permission: EntityPermissions::<T>::default_with_controller(controller),
- class_id,
- supported_schemas,
- values,
- reference_count: 0,
- }
- }
- fn get_permissions_mut(&mut self) -> &mut EntityPermissions<T> {
- &mut self.entity_permission
- }
- fn get_permissions(&self) -> &EntityPermissions<T> {
- &self.entity_permission
- }
- pub fn ensure_schema_id_is_not_added(&self, schema_id: SchemaId) -> dispatch::Result {
- let schema_not_added = !self.supported_schemas.contains(&schema_id);
- ensure!(schema_not_added, ERROR_SCHEMA_ALREADY_ADDED_TO_ENTITY);
- Ok(())
- }
- }
- decl_storage! {
- trait Store for Module<T: Trait> as ContentDirectory {
- /// Map, representing ClassId -> Class relation
- pub ClassById get(class_by_id) config(): linked_map T::ClassId => Class<T>;
- /// Map, representing EntityId -> Entity relation
- pub EntityById get(entity_by_id) config(): map T::EntityId => Entity<T>;
- /// Curator groups
- pub CuratorGroupById get(curator_group_by_id): map T::CuratorGroupId => CuratorGroup<T>;
- pub NextClassId get(next_class_id) config(): T::ClassId;
- pub NextEntityId get(next_entity_id) config(): T::EntityId;
- // The voucher associated with entity creation for a given class and controller.
- // Is updated whenever an entity is created in a given class by a given controller.
- // Constraint is updated by Root, an initial value comes from `ClassPermissions::per_controller_entity_creation_limit`.
- pub EntityCreationVouchers get(entity_creation_vouchers): double_map hasher(blake2_128) T::ClassId, blake2_128(EntityController<T>) => EntityCreationVoucher;
- /// Upper limit for how many operations can be included in a single invocation of `atomic_batched_operations`.
- pub MaximumNumberOfOperationsDuringAtomicBatching: u64;
- }
- }
- decl_module! {
- pub struct Module<T: Trait> for enum Call where origin: T::Origin {
- // ======
- // Next set of extrinsics can only be invoked by lead.
- // ======
- pub fn add_curator_group(
- origin,
- curator_group_id: T::CuratorGroupId,
- curator_group: CuratorGroup<T>
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_curator_group_does_not_exist(curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <CuratorGroupById<T>>::insert(curator_group_id, curator_group);
- Ok(())
- }
- pub fn remove_curator_group(
- origin,
- curator_group_id: T::CuratorGroupId,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_curator_group_exists(&curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <CuratorGroupById<T>>::remove(curator_group_id);
- let class_ids: Vec<T::ClassId> = <ClassById<T>>::enumerate().map(|(class_id, _)| class_id).collect();
- for class_id in class_ids {
- <ClassById<T>>::mutate(class_id, |class| {
- let class_permissions = class.get_permissions_mut();
- class_permissions.get_maintainers_mut().remove(&curator_group_id);
- })
- };
- Ok(())
- }
- pub fn set_curator_group_status(
- origin,
- curator_group_id: T::CuratorGroupId,
- is_active: bool,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_curator_group_exists(&curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
- curator_group.set_status(is_active)
- });
- Ok(())
- }
- /// Add curator to a given curator group
- pub fn add_curator(
- origin,
- curator_group_id: T::CuratorGroupId,
- curator_id: T::CuratorId,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_curator_group_exists(&curator_group_id)?;
- Self::ensure_max_number_of_curators_limit_not_reached(curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
- curator_group.get_curators_mut().insert(curator_id);
- });
- Ok(())
- }
- /// Remove curator from a given curator group
- pub fn remove_curator(
- origin,
- curator_group_id: T::CuratorGroupId,
- curator_id: T::CuratorId,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_curator_group_exists(&curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
- curator_group.get_curators_mut().remove(&curator_id);
- });
- Ok(())
- }
- /// Add curator group as specific class maintainer
- pub fn add_maintainer(
- origin,
- class_id: T::ClassId,
- curator_group_id: T::CuratorGroupId,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- Self::ensure_curator_group_exists(&curator_group_id)?;
- let class = Self::class_by_id(class_id);
- let class_permissions = class.get_permissions();
- class_permissions.ensure_maintainers_limit_not_reached()?;
- class_permissions.ensure_maintainer_does_not_exist(&curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::mutate(class_id, |class|
- class.get_permissions_mut().get_maintainers_mut().insert(curator_group_id)
- );
- Ok(())
- }
- /// Remove curator group from class maintainers set
- pub fn remove_maintainer(
- origin,
- class_id: T::ClassId,
- curator_group_id: T::CuratorGroupId,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- Self::class_by_id(class_id).get_permissions().ensure_maintainer_exists(&curator_group_id)?;
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::mutate(class_id, |class|
- class.get_permissions_mut().get_maintainers_mut().remove(&curator_group_id)
- );
- Ok(())
- }
- /// Updates or creates new entity creation voucher for given controller with individual limit
- pub fn update_entity_creation_voucher(
- origin,
- class_id: T::ClassId,
- controller: EntityController<T>,
- maximum_entities_count: CreationLimit
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- let per_controller_entity_creation_limit = Self::class_by_id(class_id).per_controller_entity_creation_limit;
- let voucher_exists = <EntityCreationVouchers<T>>::exists(class_id, &controller);
- if voucher_exists {
- // Ensure new voucher`s max entities count is less than number of already created entities in given voucher
- // and runtime entities creation constraint per actor satisfied
- Self::entity_creation_vouchers(class_id, &controller)
- .ensure_new_max_entities_count_is_valid::<T>(maximum_entities_count)?;
- }
- Self::ensure_valid_number_of_class_entities_per_actor(per_controller_entity_creation_limit, maximum_entities_count)?;
- //
- // == MUTATION SAFE ==
- //
- if voucher_exists {
- <EntityCreationVouchers<T>>::mutate(class_id, &controller, |entity_creation_voucher|
- entity_creation_voucher.set_maximum_entities_count(maximum_entities_count)
- );
- } else {
- <EntityCreationVouchers<T>>::insert(class_id, controller, EntityCreationVoucher::new(maximum_entities_count));
- }
- Ok(())
- }
- pub fn create_class(
- origin,
- name: Vec<u8>,
- description: Vec<u8>,
- class_permissions: ClassPermissions<T>,
- maximum_entities_count: CreationLimit,
- per_controller_entity_creation_limit: CreationLimit
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_entities_limits_are_valid(maximum_entities_count, per_controller_entity_creation_limit)?;
- Self::ensure_class_limit_not_reached()?;
- Self::ensure_class_name_is_valid(&name)?;
- Self::ensure_class_description_is_valid(&description)?;
- Self::ensure_class_permissions_are_valid(&class_permissions)?;
- let class_id = Self::next_class_id();
- let class = Class::new(class_permissions, name, description, maximum_entities_count, per_controller_entity_creation_limit);
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::insert(&class_id, class);
- // Increment the next class id:
- <NextClassId<T>>::mutate(|n| *n += T::ClassId::one());
- Ok(())
- }
- pub fn create_class_with_default_permissions(
- origin,
- name: Vec<u8>,
- description: Vec<u8>,
- maximum_entities_count: CreationLimit,
- per_controller_entity_creation_limit: CreationLimit
- ) -> dispatch::Result {
- Self::create_class(origin, name, description, ClassPermissions::default(), maximum_entities_count, per_controller_entity_creation_limit)
- }
- pub fn update_class_permissions(
- origin,
- class_id: T::ClassId,
- any_member: Option<bool>,
- entity_creation_blocked: Option<bool>,
- all_entity_property_values_locked: Option<bool>,
- maintainers: Option<BTreeSet<T::CuratorGroupId>>,
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- if let Some(ref maintainers) = maintainers {
- Self::ensure_curator_groups_exist(maintainers)?;
- ensure!(maintainers.len() <= T::NumberOfMaintainersConstraint::get() as usize, ERROR_NUMBER_OF_MAINTAINERS_PER_CLASS_LIMIT_REACHED);
- }
- //
- // == MUTATION SAFE ==
- //
- if let Some(any_member) = any_member {
- <ClassById<T>>::mutate(class_id, |class|
- class.get_permissions_mut().set_any_member_status(any_member)
- );
- }
- if let Some(entity_creation_blocked) = entity_creation_blocked {
- <ClassById<T>>::mutate(class_id, |class| class.get_permissions_mut().set_entity_creation_blocked(entity_creation_blocked));
- }
- if let Some(all_entity_property_values_locked) = all_entity_property_values_locked {
- <ClassById<T>>::mutate(class_id, |class|
- class.get_permissions_mut().set_all_entity_property_values_locked(all_entity_property_values_locked)
- );
- }
- if let Some(maintainers) = maintainers {
- <ClassById<T>>::mutate(class_id, |class|
- class.get_permissions_mut().set_maintainers(maintainers)
- );
- }
- Ok(())
- }
- pub fn add_class_schema(
- origin,
- class_id: T::ClassId,
- existing_properties: Vec<PropertyId>,
- new_properties: Vec<Property<T>>
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- Self::ensure_non_empty_schema(&existing_properties, &new_properties)?;
- let class = <ClassById<T>>::get(class_id);
- class.ensure_schemas_limit_not_reached()?;
- class.ensure_properties_limit_not_reached(&new_properties)?;
- let mut schema = Schema::new(existing_properties);
- let mut unique_prop_names = BTreeSet::new();
- for prop in class.properties.iter() {
- unique_prop_names.insert(prop.name.clone());
- }
- for prop in new_properties.iter() {
- prop.ensure_name_is_valid()?;
- prop.ensure_description_is_valid()?;
- prop.ensure_prop_type_size_is_valid()?;
- // Check that the name of a new property is unique within its class.
- ensure!(
- !unique_prop_names.contains(&prop.name),
- ERROR_PROP_NAME_NOT_UNIQUE_IN_A_CLASS
- );
- unique_prop_names.insert(prop.name.clone());
- }
- // Check that existing props are valid indices of class properties vector:
- let has_unknown_props = schema.get_properties()
- .iter()
- .any(|&prop_id| prop_id >= class.properties.len() as PropertyId);
- ensure!(
- !has_unknown_props,
- ERROR_CLASS_SCHEMA_REFERS_UNKNOWN_PROP_INDEX
- );
- // Check validity of Reference Types for new_properties.
- let has_unknown_reference = new_properties.iter().any(|prop| if let Type::Reference(other_class_id, _) = prop.prop_type.get_inner_type() {
- !<ClassById<T>>::exists(other_class_id)
- } else {
- false
- });
- ensure!(
- !has_unknown_reference,
- ERROR_CLASS_SCHEMA_REFERS_UNKNOWN_CLASS
- );
- let mut updated_class_props = class.properties;
- new_properties.into_iter().for_each(|prop| {
- let prop_id = updated_class_props.len() as PropertyId;
- updated_class_props.push(prop);
- schema.get_properties_mut().push(prop_id);
- });
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::mutate(class_id, |class| {
- class.properties = updated_class_props;
- class.schemas.push(schema);
- });
- Ok(())
- }
- pub fn update_class_schema_status(
- origin,
- class_id: T::ClassId,
- schema_id: SchemaId,
- schema_status: bool
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- //
- // == MUTATION SAFE ==
- //
- // Check that schema_id is a valid index of class schemas vector:
- Self::class_by_id(class_id).ensure_schema_id_exists(schema_id)?;
- <ClassById<T>>::mutate(class_id, |class| {
- class.update_schema_status(schema_id, schema_status)
- });
- Ok(())
- }
- pub fn set_class_property_lock_status_at_index(
- origin,
- class_id: T::ClassId,
- in_class_schema_property_id: PropertyId,
- is_locked: PropertyLockingPolicy
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- // Ensure property_id is a valid index of class properties vector:
- Self::class_by_id(class_id).ensure_property_id_exists(in_class_schema_property_id)?;
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::mutate(class_id, |class| {
- class.set_property_lock_status_at_index(in_class_schema_property_id, is_locked)
- });
- Ok(())
- }
- pub fn set_reference_property_same_controller_status(
- origin,
- class_id: T::ClassId,
- in_class_schema_property_id: PropertyId,
- same_controller: SameController
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_class_id(class_id)?;
- // Ensure property_id is a valid index of class properties vector:
- Self::class_by_id(class_id).ensure_property_id_exists(in_class_schema_property_id)?;
- //
- // == MUTATION SAFE ==
- //
- <ClassById<T>>::mutate(class_id, |class| {
- class.set_reference_property_same_controller_status(in_class_schema_property_id, same_controller)
- });
- Ok(())
- }
- /// Update entity permissions.
- ///
- pub fn update_entity_permissions(
- origin,
- entity_id: T::EntityId,
- controller: Option<EntityController<T>>,
- frozen_for_controller: Option<bool>,
- referenceable: Option<bool>
- ) -> dispatch::Result {
- perform_lead_auth::<T>(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- //
- // == MUTATION SAFE ==
- //
- if let Some(controller) = controller {
- // Ensure if class permissions satisfied and controller curator group exist
- <EntityById<T>>::mutate(entity_id, |inner_entity|
- inner_entity.get_permissions_mut().set_conroller(controller)
- );
- }
- if let Some(frozen_for_controller) = frozen_for_controller {
- <EntityById<T>>::mutate(entity_id, |inner_entity|
- inner_entity.get_permissions_mut().set_frozen(frozen_for_controller)
- );
- }
- if let Some(referenceable) = referenceable {
- <EntityById<T>>::mutate(entity_id, |inner_entity|
- inner_entity.get_permissions_mut().set_referencable(referenceable)
- );
- }
- Ok(())
- }
- // ======
- // The next set of extrinsics can be invoked by anyone who can properly sign for provided value of `Actor<T>`.
- // ======
- /// Create an entity.
- /// If someone is making an entity of this class for first time, then a voucher is also added with the class limit as the default limit value.
- /// class limit default value.
- pub fn create_entity(
- origin,
- class_id: T::ClassId,
- actor: Actor<T>,
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- let class = Self::ensure_class_exists(class_id)?;
- class.ensure_maximum_entities_count_limit_not_reached()?;
- let class_permissions = class.get_permissions();
- class_permissions.ensure_entity_creation_not_blocked()?;
- class_permissions.ensure_can_create_entities(&account_id, &actor)?;
- let entity_controller = EntityController::from_actor(&actor);
- // Check if entity creation voucher exists
- let voucher_exists = if <EntityCreationVouchers<T>>::exists(class_id, &entity_controller) {
- let entity_creation_voucher = Self::entity_creation_vouchers(class_id, &entity_controller);
- // Ensure voucher limit not reached
- Self::ensure_voucher_limit_not_reached(entity_creation_voucher)?;
- true
- } else {
- false
- };
- //
- // == MUTATION SAFE ==
- //
- if voucher_exists {
- // Increment number of created entities count, if voucher already exist
- <EntityCreationVouchers<T>>::mutate(class_id, &entity_controller, |entity_creation_voucher| {
- entity_creation_voucher.increment_created_entities_count()
- });
- } else {
- // Create new voucher for given entity creator with default limit and increment created entities count
- let mut entity_creation_voucher = EntityCreationVoucher::new(class.get_controller_entity_creation_limit());
- entity_creation_voucher.increment_created_entities_count();
- <EntityCreationVouchers<T>>::insert(class_id, entity_controller.clone(), entity_creation_voucher);
- }
- Self::complete_entity_creation(class_id, entity_controller);
- Ok(())
- }
- pub fn remove_entity(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (_, access_level) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- EntityPermissions::<T>::ensure_group_can_remove_entity(access_level)?;
- // Ensure there is no property values pointing to the given entity
- Self::ensure_rc_is_zero(entity_id)?;
- //
- // == MUTATION SAFE ==
- //
- Self::complete_entity_removal(entity_id);
- Ok(())
- }
- pub fn add_schema_support_to_entity(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- schema_id: SchemaId,
- property_values: BTreeMap<PropertyId, PropertyValue<T>>
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (entity, _) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- let class = Self::class_by_id(entity.class_id);
- // Check that schema_id is a valid index of class schemas vector:
- class.ensure_schema_id_exists(schema_id)?;
- // Ensure class schema is active
- class.ensure_schema_is_active(schema_id)?;
- // Check that schema id is not yet added to this entity
- entity.ensure_schema_id_is_not_added(schema_id)?;
- let class_schema_opt = class.schemas.get(schema_id as usize);
- let schema_prop_ids = class_schema_opt.unwrap().get_properties();
- let current_entity_values = entity.values.clone();
- let mut appended_entity_values = entity.values.clone();
- let mut entities_rc_to_increment_vec = vec![];
- for prop_id in schema_prop_ids.iter() {
- if current_entity_values.contains_key(prop_id) {
- // A property is already added to the entity and cannot be updated
- // while adding a schema support to this entity.
- continue;
- }
- Self::add_new_property_value(&class, &entity, *prop_id, &property_values, &mut entities_rc_to_increment_vec, &mut appended_entity_values)?;
- }
- //
- // == MUTATION SAFE ==
- //
- <EntityById<T>>::mutate(entity_id, |entity| {
- // Add a new schema to the list of schemas supported by this entity.
- entity.supported_schemas.insert(schema_id);
- // Update entity values only if new properties have been added.
- if appended_entity_values.len() > entity.values.len() {
- entity.values = appended_entity_values;
- }
- });
- entities_rc_to_increment_vec
- .iter()
- .for_each(|entities_rc_to_increment| {
- Self::increment_entities_rc(entities_rc_to_increment);
- });
- Ok(())
- }
- pub fn update_entity_property_values(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- new_property_values: BTreeMap<PropertyId, PropertyValue<T>>
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (entity, access_level) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- let class = Self::class_by_id(entity.class_id);
- // Ensure property values were not locked on class level
- ensure!(
- !class.get_permissions().all_entity_property_values_locked(),
- ERROR_ALL_PROP_WERE_LOCKED_ON_CLASS_LEVEL
- );
- // Get current property values of an entity as a mutable vector,
- // so we can update them if new values provided present in new_property_values.
- let mut updated_values = entity.values.clone();
- let mut updated = false;
- let mut entities_rc_to_increment_vec = vec![];
- let mut entities_rc_to_decrement_vec = vec![];
- // Iterate over a vector of new values and update corresponding properties
- // of this entity if new values are valid.
- for (id, new_value) in new_property_values.into_iter() {
- // Try to find a current property value in the entity
- // by matching its id to the id of a property with an updated value.
- let current_prop_value = updated_values
- .get_mut(&id)
- // Throw an error if a property was not found on entity
- // by an in-class index of a property update.
- .ok_or(ERROR_UNKNOWN_ENTITY_PROP_ID)?;
- // Skip update if new value is equal to the current one or class property type
- // is locked for update from current actor
- if new_value == *current_prop_value {
- continue;
- } else {
- let (mut temp_entities_rc_to_increment_vec, mut temp_entities_rc_to_decrement_vec) = Self::perform_entity_property_value_update(&class, &entity, id, access_level, new_value, current_prop_value)?;
- entities_rc_to_increment_vec.append(&mut temp_entities_rc_to_increment_vec);
- entities_rc_to_decrement_vec.append(&mut temp_entities_rc_to_decrement_vec);
- updated = true;
- }
- }
- // If property values should be updated:
- if updated {
- //
- // == MUTATION SAFE ==
- //
- <EntityById<T>>::mutate(entity_id, |entity| {
- entity.values = updated_values;
- });
- entities_rc_to_increment_vec
- .iter()
- .for_each(|entities_rc_to_increment| {
- Self::increment_entities_rc(entities_rc_to_increment);
- });
- entities_rc_to_decrement_vec
- .iter()
- .for_each(|entities_rc_to_decrement| {
- Self::decrement_entities_rc(entities_rc_to_decrement);
- });
- }
- Ok(())
- }
- pub fn clear_entity_property_vector(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- in_class_schema_property_id: PropertyId
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (entity, access_level) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- let current_property_value_vec =
- Self::get_property_value_vec(&entity, in_class_schema_property_id)?;
- Self::ensure_class_property_type_unlocked_for(
- entity.class_id,
- in_class_schema_property_id,
- access_level,
- )?;
- let entities_rc_to_decrement = current_property_value_vec
- .get_vec_value()
- .get_involved_entities();
- //
- // == MUTATION SAFE ==
- //
- // Clear property value vector:
- <EntityById<T>>::mutate(entity_id, |entity| {
- if let Some(PropertyValue::Vector(current_property_value_vec)) =
- entity.values.get_mut(&in_class_schema_property_id)
- {
- current_property_value_vec.vec_clear();
- }
- if let Some(entities_rc_to_decrement) = entities_rc_to_decrement {
- Self::decrement_entities_rc(&entities_rc_to_decrement);
- }
- });
- Ok(())
- }
- pub fn remove_at_entity_property_vector(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- in_class_schema_property_id: PropertyId,
- index_in_property_vec: VecMaxLength,
- nonce: T::Nonce
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (entity, access_level) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- let current_property_value_vec =
- Self::get_property_value_vec(&entity, in_class_schema_property_id)?;
- Self::ensure_class_property_type_unlocked_for(
- entity.class_id,
- in_class_schema_property_id,
- access_level,
- )?;
- // Ensure property value vector nonces equality to avoid possible data races,
- // when performing vector specific operations
- current_property_value_vec.ensure_nonce_equality(nonce)?;
- current_property_value_vec
- .ensure_index_in_property_vector_is_valid(index_in_property_vec)?;
- let involved_entity_id = current_property_value_vec
- .get_vec_value()
- .get_involved_entities()
- .map(|involved_entities| involved_entities[index_in_property_vec as usize]);
- //
- // == MUTATION SAFE ==
- //
- // Remove property value vector
- <EntityById<T>>::mutate(entity_id, |entity| {
- if let Some(PropertyValue::Vector(current_prop_value)) =
- entity.values.get_mut(&in_class_schema_property_id)
- {
- current_prop_value.vec_remove_at(index_in_property_vec)
- }
- });
- if let Some(involved_entity_id) = involved_entity_id {
- <EntityById<T>>::mutate(involved_entity_id, |entity| entity.reference_count -= 1)
- }
- Ok(())
- }
- pub fn insert_at_entity_property_vector(
- origin,
- actor: Actor<T>,
- entity_id: T::EntityId,
- in_class_schema_property_id: PropertyId,
- index_in_property_vec: VecMaxLength,
- property_value: SinglePropertyValue<T>,
- nonce: T::Nonce
- ) -> dispatch::Result {
- let account_id = ensure_signed(origin)?;
- Self::ensure_known_entity_id(entity_id)?;
- let (entity, access_level) = Self::get_entity_and_access_level(account_id, entity_id, actor)?;
- // Try to find a current property value in the entity
- // by matching its id to the id of a property with an updated value.
- if let Some(PropertyValue::Vector(entity_prop_value)) =
- entity.values.get(&in_class_schema_property_id)
- {
- let class_prop = Self::ensure_class_property_type_unlocked_for(
- entity.class_id,
- in_class_schema_property_id,
- access_level,
- )?;
- // Ensure property value vector nonces equality to avoid possible data races,
- // when performing vector specific operations
- entity_prop_value.ensure_nonce_equality(nonce)?;
- // Validate a new property value against the type of this property
- // and check any additional constraints like the length of a vector
- // if it's a vector property or the length of a text if it's a text property.
- class_prop.ensure_prop_value_can_be_inserted_at_prop_vec(
- &property_value,
- entity_prop_value,
- index_in_property_vec,
- entity.get_permissions().get_controller(),
- )?;
- };
- //
- // == MUTATION SAFE ==
- //
- // Insert property value into property value vector
- <EntityById<T>>::mutate(entity_id, |entity| {
- let value = property_value.get_value();
- if let Some(entities_rc_to_increment) = value.get_involved_entity() {
- Self::increment_entities_rc(&[entities_rc_to_increment]);
- }
- if let Some(PropertyValue::Vector(current_prop_value)) =
- entity.values.get_mut(&in_class_schema_property_id)
- {
- current_prop_value.vec_insert_at(index_in_property_vec, value)
- }
- });
- Ok(())
- }
- pub fn transaction(origin, actor: Actor<T>, operations: Vec<OperationType<T>>) -> dispatch::Result {
- // This map holds the T::EntityId of the entity created as a result of executing a CreateEntity Operation
- // keyed by the indexed of the operation, in the operations vector.
- let mut entity_created_in_operation: BTreeMap<usize, T::EntityId> = BTreeMap::new();
- let raw_origin = origin.into().map_err(|_| ERROR_ORIGIN_CANNOT_BE_MADE_INTO_RAW_ORIGIN)?;
- for (op_index, operation_type) in operations.into_iter().enumerate() {
- let origin = T::Origin::from(raw_origin.clone());
- let actor = actor.clone();
- match operation_type {
- OperationType::CreateEntity(create_entity_operation) => {
- Self::create_entity(origin, create_entity_operation.class_id, actor)?;
- // entity id of newly created entity
- let entity_id = Self::next_entity_id() - T::EntityId::one();
- entity_created_in_operation.insert(op_index, entity_id);
- },
- OperationType::UpdatePropertyValues(update_property_values_operation) => {
- let entity_id = operations::parametrized_entity_to_entity_id(&entity_created_in_operation, update_property_values_operation.entity_id)?;
- let property_values = operations::parametrized_property_values_to_property_values(&entity_created_in_operation, update_property_values_operation.new_parametrized_property_values)?;
- Self::update_entity_property_values(origin, actor, entity_id, property_values)?;
- },
- OperationType::AddSchemaSupportToEntity(add_schema_support_to_entity_operation) => {
- let entity_id = operations::parametrized_entity_to_entity_id(&entity_created_in_operation, add_schema_support_to_entity_operation.entity_id)?;
- let schema_id = add_schema_support_to_entity_operation.schema_id;
- let property_values = operations::parametrized_property_values_to_property_values(&entity_created_in_operation, add_schema_support_to_entity_operation.parametrized_property_values)?;
- Self::add_schema_support_to_entity(origin, actor, entity_id, schema_id, property_values)?;
- }
- }
- }
- Ok(())
- }
- }
- }
- impl<T: Trait> Module<T> {
- fn complete_entity_creation(class_id: T::ClassId, entity_controller: EntityController<T>) {
- let entity_id = Self::next_entity_id();
- let new_entity = Entity::<T>::new(
- entity_controller,
- class_id,
- BTreeSet::new(),
- BTreeMap::new(),
- );
- // Save newly created entity:
- EntityById::insert(entity_id, new_entity);
- // Increment the next entity id:
- <NextEntityId<T>>::mutate(|n| *n += T::EntityId::one());
- <ClassById<T>>::mutate(class_id, |class| {
- class.increment_entities_count();
- });
- }
- fn complete_entity_removal(entity_id: T::EntityId) {
- let class_id = Self::get_class_id_by_entity_id(entity_id);
- <EntityById<T>>::remove(entity_id);
- <ClassById<T>>::mutate(class_id, |class| class.decrement_entities_count());
- }
- fn increment_entities_rc(entity_ids: &[T::EntityId]) {
- entity_ids.iter().for_each(|entity_id| {
- <EntityById<T>>::mutate(entity_id, |entity| entity.reference_count += 1)
- });
- }
- fn decrement_entities_rc(entity_ids: &[T::EntityId]) {
- entity_ids.iter().for_each(|entity_id| {
- <EntityById<T>>::mutate(entity_id, |entity| entity.reference_count -= 1)
- });
- }
- /// Returns the stored class if exist, error otherwise.
- fn ensure_class_exists(class_id: T::ClassId) -> Result<Class<T>, &'static str> {
- ensure!(<ClassById<T>>::exists(class_id), ERROR_CLASS_NOT_FOUND);
- Ok(Self::class_by_id(class_id))
- }
- /// Add property value, if was not already povided for the property of this schema
- fn add_new_property_value(
- class: &Class<T>,
- entity: &Entity<T>,
- prop_id: PropertyId,
- property_values: &BTreeMap<PropertyId, PropertyValue<T>>,
- entities_rc_to_increment_vec: &mut Vec<Vec<T::EntityId>>,
- appended_entity_values: &mut BTreeMap<PropertyId, PropertyValue<T>>,
- ) -> Result<(), &'static str> {
- let class_prop = &class.properties[prop_id as usize];
- if let Some(new_value) = property_values.get(&prop_id) {
- class_prop.ensure_property_value_to_update_is_valid(
- new_value,
- entity.get_permissions().get_controller(),
- )?;
- if let Some(entities_rc_to_increment) = new_value.get_involved_entities() {
- entities_rc_to_increment_vec.push(entities_rc_to_increment);
- }
- appended_entity_values.insert(prop_id, new_value.to_owned());
- } else {
- // All required prop values should be provided
- ensure!(!class_prop.required, ERROR_MISSING_REQUIRED_PROP);
- // Add all missing non required schema prop values as PropertyValue::default()
- appended_entity_values.insert(prop_id, PropertyValue::default());
- }
- Ok(())
- }
- pub fn perform_entity_property_value_update(
- class: &Class<T>,
- entity: &Entity<T>,
- id: PropertyId,
- access_level: EntityAccessLevel,
- new_value: PropertyValue<T>,
- current_prop_value: &mut PropertyValue<T>,
- ) -> Result<(EntitiesRcVec<T>, EntitiesRcVec<T>), &'static str> {
- let mut entities_rc_to_increment_vec = vec![];
- let mut entities_rc_to_decrement_vec = vec![];
- // Get class-level information about this property
- if let Some(class_prop) = class.properties.get(id as usize) {
- // Ensure class property is unlocked for given actor
- ensure!(
- !class_prop.is_locked_from(access_level),
- ERROR_CLASS_PROPERTY_TYPE_IS_LOCKED_FOR_GIVEN_ACTOR
- );
- // Validate a new property value against the type of this property
- // and check any additional constraints like the length of a vector
- // if it's a vector property or the length of a text if it's a text property.
- class_prop.ensure_property_value_to_update_is_valid(
- &new_value,
- entity.get_permissions().get_controller(),
- )?;
- // Get unique entity ids to update rc
- if let (Some(entities_rc_to_increment), Some(entities_rc_to_decrement)) = (
- new_value.get_involved_entities(),
- current_prop_value.get_involved_entities(),
- ) {
- let (entities_rc_to_decrement, entities_rc_to_increment): (
- Vec<T::EntityId>,
- Vec<T::EntityId>,
- ) = entities_rc_to_decrement
- .into_iter()
- .zip(entities_rc_to_increment.into_iter())
- .filter(|(entity_rc_to_decrement, entity_rc_to_increment)| {
- entity_rc_to_decrement != entity_rc_to_increment
- })
- .unzip();
- entities_rc_to_increment_vec.push(entities_rc_to_increment);
- entities_rc_to_decrement_vec.push(entities_rc_to_decrement);
- }
- // Update a current prop value in a mutable vector, if a new value is valid.
- current_prop_value.update(new_value);
- }
- Ok((entities_rc_to_increment_vec, entities_rc_to_decrement_vec))
- }
- fn get_property_value_vec(
- entity: &Entity<T>,
- in_class_schema_property_id: PropertyId,
- ) -> Result<&VecPropertyValue<T>, &'static str> {
- entity
- .values
- .get(&in_class_schema_property_id)
- // Throw an error if a property was not found on entity
- // by an in-class index of a property.
- .ok_or(ERROR_UNKNOWN_ENTITY_PROP_ID)?
- .as_vec_property_value()
- // Ensure prop value under given class schema property id is vector
- .ok_or(ERROR_PROP_VALUE_UNDER_GIVEN_INDEX_IS_NOT_A_VECTOR)
- }
- fn get_entity_and_access_level(
- account_id: T::AccountId,
- entity_id: T::EntityId,
- actor: Actor<T>,
- ) -> Result<(Entity<T>, EntityAccessLevel), &'static str> {
- let (entity, class) = Self::get_entity_and_class(entity_id);
- let access_level = EntityAccessLevel::derive(
- &account_id,
- entity.get_permissions(),
- class.get_permissions(),
- actor,
- )?;
- Ok((entity, access_level))
- }
- pub fn get_entity_and_class(entity_id: T::EntityId) -> (Entity<T>, Class<T>) {
- let entity = <EntityById<T>>::get(entity_id);
- let class = ClassById::get(entity.class_id);
- (entity, class)
- }
- pub fn get_class_id_by_entity_id(entity_id: T::EntityId) -> T::ClassId {
- <EntityById<T>>::get(entity_id).class_id
- }
- pub fn ensure_class_property_type_unlocked_for(
- class_id: T::ClassId,
- in_class_schema_property_id: PropertyId,
- entity_access_level: EntityAccessLevel,
- ) -> Result<Property<T>, &'static str> {
- let class = Self::class_by_id(class_id);
- // Ensure property values were not locked on class level
- ensure!(
- !class.get_permissions().all_entity_property_values_locked(),
- ERROR_ALL_PROP_WERE_LOCKED_ON_CLASS_LEVEL
- );
- // Get class-level information about this property
- let class_prop = class
- .properties
- .get(in_class_schema_property_id as usize)
- // Throw an error if a property was not found on class
- // by an in-class index of a property.
- .ok_or(ERROR_CLASS_PROP_NOT_FOUND)?;
- ensure!(
- !class_prop.is_locked_from(entity_access_level),
- ERROR_CLASS_PROPERTY_TYPE_IS_LOCKED_FOR_GIVEN_ACTOR
- );
- Ok(class_prop.to_owned())
- }
- pub fn ensure_known_class_id(class_id: T::ClassId) -> dispatch::Result {
- ensure!(<ClassById<T>>::exists(class_id), ERROR_CLASS_NOT_FOUND);
- Ok(())
- }
- pub fn ensure_known_entity_id(entity_id: T::EntityId) -> dispatch::Result {
- ensure!(<EntityById<T>>::exists(entity_id), ERROR_ENTITY_NOT_FOUND);
- Ok(())
- }
- pub fn ensure_rc_is_zero(entity_id: T::EntityId) -> dispatch::Result {
- let entity = Self::entity_by_id(entity_id);
- ensure!(
- entity.reference_count == 0,
- ERROR_ENTITY_REFERENCE_COUNTER_DOES_NOT_EQUAL_TO_ZERO
- );
- Ok(())
- }
- pub fn ensure_curator_group_exists(group_id: &T::CuratorGroupId) -> dispatch::Result {
- ensure!(
- <CuratorGroupById<T>>::exists(group_id),
- ERROR_CURATOR_GROUP_DOES_NOT_EXIST
- );
- Ok(())
- }
- pub fn ensure_voucher_limit_not_reached(voucher: EntityCreationVoucher) -> dispatch::Result {
- ensure!(voucher.limit_not_reached(), ERROR_VOUCHER_LIMIT_REACHED);
- Ok(())
- }
- pub fn ensure_curator_group_does_not_exist(group_id: T::CuratorGroupId) -> dispatch::Result {
- ensure!(
- !<CuratorGroupById<T>>::exists(group_id),
- ERROR_CURATOR_GROUP_ALREADY_EXISTS
- );
- Ok(())
- }
- pub fn ensure_curator_groups_exist(
- curator_groups: &BTreeSet<T::CuratorGroupId>,
- ) -> dispatch::Result {
- for curator_group in curator_groups {
- Self::ensure_curator_group_exists(curator_group)?;
- }
- Ok(())
- }
- pub fn ensure_max_number_of_curators_limit_not_reached(
- group_id: T::CuratorGroupId,
- ) -> dispatch::Result {
- let curator_group = Self::curator_group_by_id(group_id);
- ensure!(
- curator_group.get_curators().len() < T::NumberOfCuratorsConstraint::get() as usize,
- ERROR_NUMBER_OF_CURATORS_PER_GROUP_LIMIT_REACHED
- );
- Ok(())
- }
- pub fn ensure_class_permissions_are_valid(
- class_permissions: &ClassPermissions<T>,
- ) -> dispatch::Result {
- class_permissions.ensure_maintainers_limit_not_reached()?;
- Self::ensure_curator_groups_exist(class_permissions.get_maintainers())?;
- Ok(())
- }
- pub fn ensure_non_empty_schema(
- existing_properties: &[PropertyId],
- new_properties: &[Property<T>],
- ) -> dispatch::Result {
- let non_empty_schema = !existing_properties.is_empty() || !new_properties.is_empty();
- ensure!(non_empty_schema, ERROR_NO_PROPS_IN_CLASS_SCHEMA);
- Ok(())
- }
- pub fn ensure_class_name_is_valid(text: &[u8]) -> dispatch::Result {
- T::ClassNameConstraint::get().ensure_valid(
- text.len(),
- ERROR_CLASS_NAME_TOO_SHORT,
- ERROR_CLASS_NAME_TOO_LONG,
- )
- }
- pub fn ensure_class_description_is_valid(text: &[u8]) -> dispatch::Result {
- T::ClassDescriptionConstraint::get().ensure_valid(
- text.len(),
- ERROR_CLASS_DESCRIPTION_TOO_SHORT,
- ERROR_CLASS_DESCRIPTION_TOO_LONG,
- )
- }
- pub fn ensure_class_limit_not_reached() -> dispatch::Result {
- ensure!(
- T::NumberOfClassesConstraint::get() < <ClassById<T>>::enumerate().count() as MaxNumber,
- ERROR_CLASS_LIMIT_REACHED
- );
- Ok(())
- }
- pub fn ensure_valid_number_of_entities_per_class(
- maximum_entities_count: CreationLimit,
- ) -> dispatch::Result {
- ensure!(
- maximum_entities_count < T::EntitiesCreationConstraint::get(),
- ERROR_ENTITIES_NUMBER_PER_CLASS_CONSTRAINT_VIOLATED
- );
- Ok(())
- }
- pub fn ensure_valid_number_of_class_entities_per_actor_constraint(
- per_controller_entity_creation_limit: CreationLimit,
- ) -> dispatch::Result {
- ensure!(
- per_controller_entity_creation_limit < T::IndividualEntitiesCreationConstraint::get(),
- ERROR_NUMBER_OF_CLASS_ENTITIES_PER_ACTOR_CONSTRAINT_VIOLATED
- );
- Ok(())
- }
- pub fn ensure_valid_number_of_class_entities_per_actor(
- // per class individual controller entity creation limit
- per_controller_entity_creation_limit: CreationLimit,
- maximum_entities_count: CreationLimit,
- ) -> dispatch::Result {
- ensure!(
- per_controller_entity_creation_limit >= maximum_entities_count,
- ERROR_INDIVIDUAL_NUMBER_OF_CLASS_ENTITIES_PER_ACTOR_IS_TOO_BIG
- );
- Ok(())
- }
- pub fn ensure_entities_limits_are_valid(
- maximum_entities_count: CreationLimit,
- per_controller_entities_creation_limit: CreationLimit,
- ) -> dispatch::Result {
- ensure!(
- per_controller_entities_creation_limit < maximum_entities_count,
- ERROR_PER_CONTROLLER_ENTITIES_CREATION_LIMIT_EXCEEDS_OVERALL_LIMIT
- );
- Self::ensure_valid_number_of_entities_per_class(maximum_entities_count)?;
- Self::ensure_valid_number_of_class_entities_per_actor_constraint(
- per_controller_entities_creation_limit,
- )
- }
- }
|