lib.rs 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. use codec::{Codec, Decode, Encode};
  4. use rstd::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
  5. use rstd::prelude::*;
  6. use runtime_primitives::traits::{MaybeSerialize, Member, SimpleArithmetic};
  7. use srml_support::{decl_module, decl_storage, dispatch, ensure, traits::Get, Parameter};
  8. use system;
  9. #[cfg(feature = "std")]
  10. pub use serde::{Deserialize, Serialize};
  11. // EntityId, ClassId -> should be configured on content_directory::Trait
  12. mod constraint;
  13. mod credentials;
  14. mod errors;
  15. mod example;
  16. mod mock;
  17. mod operations;
  18. mod permissions;
  19. mod tests;
  20. pub use constraint::*;
  21. pub use credentials::*;
  22. pub use errors::*;
  23. pub use operations::*;
  24. pub use permissions::*;
  25. pub trait Trait: system::Trait {
  26. /// Type that represents an actor or group of actors in the system.
  27. type Credential: Parameter
  28. + Member
  29. + SimpleArithmetic
  30. + Codec
  31. + Default
  32. + Copy
  33. + Clone
  34. + MaybeSerialize
  35. + Eq
  36. + PartialEq
  37. + Ord;
  38. /// Security/configuration constraints
  39. type PropertyNameConstraint: Get<InputValidationLengthConstraint>;
  40. type PropertyDescriptionConstraint: Get<InputValidationLengthConstraint>;
  41. type ClassNameConstraint: Get<InputValidationLengthConstraint>;
  42. type ClassDescriptionConstraint: Get<InputValidationLengthConstraint>;
  43. /// External type for checking if an account has specified credential.
  44. type CredentialChecker: CredentialChecker<Self>;
  45. /// External type used to check if an account has permission to create new Classes.
  46. type CreateClassPermissionsChecker: CreateClassPermissionsChecker<Self>;
  47. }
  48. /// Trait for checking if an account has specified Credential
  49. pub trait CredentialChecker<T: Trait> {
  50. fn account_has_credential(account: &T::AccountId, credential: T::Credential) -> bool;
  51. }
  52. /// An implementation where no account has any credential. Effectively
  53. /// only the system will be able to perform any action on the versioned store.
  54. impl<T: Trait> CredentialChecker<T> for () {
  55. fn account_has_credential(_account: &T::AccountId, _credential: T::Credential) -> bool {
  56. false
  57. }
  58. }
  59. /// An implementation that calls into multiple checkers. This allows for multiple modules
  60. /// to maintain AccountId to Credential mappings.
  61. impl<T: Trait, X: CredentialChecker<T>, Y: CredentialChecker<T>> CredentialChecker<T> for (X, Y) {
  62. fn account_has_credential(account: &T::AccountId, group: T::Credential) -> bool {
  63. X::account_has_credential(account, group) || Y::account_has_credential(account, group)
  64. }
  65. }
  66. /// Trait for externally checking if an account can create new classes in the versioned store.
  67. pub trait CreateClassPermissionsChecker<T: Trait> {
  68. fn account_can_create_class_permissions(account: &T::AccountId) -> bool;
  69. }
  70. /// An implementation that does not permit any account to create classes. Effectively
  71. /// only the system can create classes.
  72. impl<T: Trait> CreateClassPermissionsChecker<T> for () {
  73. fn account_can_create_class_permissions(_account: &T::AccountId) -> bool {
  74. false
  75. }
  76. }
  77. /// Length constraint for input validation
  78. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  79. #[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, Debug)]
  80. pub struct InputValidationLengthConstraint {
  81. /// Minimum length
  82. pub min: u16,
  83. /// Difference between minimum length and max length.
  84. /// While having max would have been more direct, this
  85. /// way makes max < min unrepresentable semantically,
  86. /// which is safer.
  87. pub max_min_diff: u16,
  88. }
  89. impl InputValidationLengthConstraint {
  90. pub fn new(min: u16, max_min_diff: u16) -> Self {
  91. Self { min, max_min_diff }
  92. }
  93. /// Helper for computing max
  94. pub fn max(&self) -> u16 {
  95. self.min + self.max_min_diff
  96. }
  97. pub fn ensure_valid(
  98. &self,
  99. len: usize,
  100. too_short_msg: &'static str,
  101. too_long_msg: &'static str,
  102. ) -> Result<(), &'static str> {
  103. let length = len as u16;
  104. if length < self.min {
  105. Err(too_short_msg)
  106. } else if length > self.max() {
  107. Err(too_long_msg)
  108. } else {
  109. Ok(())
  110. }
  111. }
  112. }
  113. pub type ClassId = u64;
  114. pub type EntityId = u64;
  115. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  116. #[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
  117. pub struct Class<T: Trait> {
  118. /// Permissions for an instance of a Class in the versioned store.
  119. #[cfg_attr(feature = "std", serde(skip))]
  120. class_permissions: ClassPermissionsType<T>,
  121. /// All properties that have been used on this class across different class schemas.
  122. /// Unlikely to be more than roughly 20 properties per class, often less.
  123. /// For Person, think "height", "weight", etc.
  124. pub properties: Vec<Property>,
  125. /// All scehmas that are available for this class, think v0.0 Person, v.1.0 Person, etc.
  126. pub schemas: Vec<Schema>,
  127. pub name: Vec<u8>,
  128. pub description: Vec<u8>,
  129. }
  130. impl<T: Trait> Default for Class<T> {
  131. fn default() -> Self {
  132. Self {
  133. class_permissions: ClassPermissionsType::<T>::default(),
  134. properties: vec![],
  135. schemas: vec![],
  136. name: vec![],
  137. description: vec![],
  138. }
  139. }
  140. }
  141. impl<T: Trait> Class<T> {
  142. fn new(
  143. class_permissions: ClassPermissionsType<T>,
  144. name: Vec<u8>,
  145. description: Vec<u8>,
  146. ) -> Self {
  147. Self {
  148. class_permissions,
  149. properties: vec![],
  150. schemas: vec![],
  151. name,
  152. description,
  153. }
  154. }
  155. fn is_active_schema(&self, schema_index: u16) -> bool {
  156. // Such indexing is safe, when length bounds were previously checked
  157. self.schemas[schema_index as usize].is_active
  158. }
  159. fn update_schema_status(&mut self, schema_index: u16, schema_status: bool) {
  160. // Such indexing is safe, when length bounds were previously checked
  161. self.schemas[schema_index as usize].is_active = schema_status;
  162. }
  163. fn get_permissions_mut(&mut self) -> &mut ClassPermissionsType<T> {
  164. &mut self.class_permissions
  165. }
  166. fn get_permissions(&self) -> &ClassPermissionsType<T> {
  167. &self.class_permissions
  168. }
  169. fn refresh_last_permissions_update(&mut self) {
  170. self.class_permissions.last_permissions_update = <system::Module<T>>::block_number();
  171. }
  172. }
  173. pub type ClassPermissionsType<T> =
  174. ClassPermissions<ClassId, <T as Trait>::Credential, u16, <T as system::Trait>::BlockNumber>;
  175. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  176. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  177. pub struct Entity {
  178. /// The class id of this entity.
  179. pub class_id: ClassId,
  180. /// What schemas under which this entity of a class is available, think
  181. /// v.2.0 Person schema for John, v3.0 Person schema for John
  182. /// Unlikely to be more than roughly 20ish, assuming schemas for a given class eventually stableize, or that very old schema are eventually removed.
  183. pub supported_schemas: BTreeSet<u16>, // indices of schema in corresponding class
  184. /// Values for properties on class that are used by some schema used by this entity!
  185. /// Length is no more than Class.properties.
  186. pub values: BTreeMap<u16, PropertyValue>,
  187. // pub deleted: bool,
  188. }
  189. /// A schema defines what properties describe an entity
  190. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  191. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  192. pub struct Schema {
  193. /// Indices into properties vector for the corresponding class.
  194. pub properties: Vec<u16>,
  195. pub is_active: bool,
  196. }
  197. impl Default for Schema {
  198. fn default() -> Self {
  199. Self {
  200. properties: vec![],
  201. // Default schema status
  202. is_active: true,
  203. }
  204. }
  205. }
  206. impl Schema {
  207. fn new(properties: Vec<u16>) -> Self {
  208. Self {
  209. properties,
  210. // Default schema status
  211. is_active: true,
  212. }
  213. }
  214. }
  215. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  216. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
  217. pub struct Property {
  218. pub prop_type: PropertyType,
  219. pub required: bool,
  220. pub name: Vec<u8>,
  221. pub description: Vec<u8>,
  222. }
  223. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  224. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  225. pub enum PropertyType {
  226. // Single value:
  227. Bool,
  228. Uint16,
  229. Uint32,
  230. Uint64,
  231. Int16,
  232. Int32,
  233. Int64,
  234. Text(u16),
  235. Reference(ClassId),
  236. // Vector of values.
  237. // The first u16 value is the max length of this vector.
  238. BoolVec(u16),
  239. Uint16Vec(u16),
  240. Uint32Vec(u16),
  241. Uint64Vec(u16),
  242. Int16Vec(u16),
  243. Int32Vec(u16),
  244. Int64Vec(u16),
  245. /// The first u16 value is the max length of this vector.
  246. /// The second u16 value is the max length of every text item in this vector.
  247. TextVec(u16, u16),
  248. /// The first u16 value is the max length of this vector.
  249. /// The second ClassId value tells that an every element of this vector
  250. /// should be of a specific ClassId.
  251. ReferenceVec(u16, ClassId),
  252. // External(ExternalProperty),
  253. // ExternalVec(u16, ExternalProperty),
  254. }
  255. impl Default for PropertyType {
  256. fn default() -> Self {
  257. PropertyType::Bool
  258. }
  259. }
  260. #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
  261. #[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
  262. pub enum PropertyValue {
  263. // Single value:
  264. Bool(bool),
  265. Uint16(u16),
  266. Uint32(u32),
  267. Uint64(u64),
  268. Int16(i16),
  269. Int32(i32),
  270. Int64(i64),
  271. Text(Vec<u8>),
  272. Reference(EntityId),
  273. // Vector of values:
  274. BoolVec(Vec<bool>),
  275. Uint16Vec(Vec<u16>),
  276. Uint32Vec(Vec<u32>),
  277. Uint64Vec(Vec<u64>),
  278. Int16Vec(Vec<i16>),
  279. Int32Vec(Vec<i32>),
  280. Int64Vec(Vec<i64>),
  281. TextVec(Vec<Vec<u8>>),
  282. ReferenceVec(Vec<EntityId>),
  283. // External(ExternalPropertyType),
  284. // ExternalVec(Vec<ExternalPropertyType>),
  285. }
  286. impl Default for PropertyValue {
  287. fn default() -> Self {
  288. PropertyValue::Bool(false)
  289. }
  290. }
  291. // Shortcuts for faster readability of match expression:
  292. use PropertyType as PT;
  293. use PropertyValue as PV;
  294. decl_storage! {
  295. trait Store for Module<T: Trait> as ContentDirectory {
  296. /// ClassPermissions of corresponding Classes in the versioned store
  297. pub ClassById get(class_by_id) config(): linked_map ClassId => Class<T>;
  298. pub EntityById get(entity_by_id) config(): map EntityId => Entity;
  299. /// Owner of an entity in the versioned store. If it is None then it is owned by the system.
  300. pub EntityMaintainerByEntityId get(entity_maintainer_by_entity_id): linked_map EntityId => Option<T::Credential>;
  301. pub NextClassId get(next_class_id) config(): ClassId;
  302. pub NextEntityId get(next_entity_id) config(): EntityId;
  303. }
  304. }
  305. decl_module! {
  306. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  307. /// Sets the admins for a class
  308. fn set_class_admins(
  309. origin,
  310. class_id: ClassId,
  311. admins: CredentialSet<T::Credential>
  312. ) -> dispatch::Result {
  313. let raw_origin = Self::ensure_root_or_signed(origin)?;
  314. Self::mutate_class_permissions(
  315. &raw_origin,
  316. None,
  317. Self::is_system, // root origin
  318. class_id,
  319. |class_permissions| {
  320. class_permissions.admins = admins;
  321. Ok(())
  322. }
  323. )
  324. }
  325. // Methods for updating concrete permissions
  326. fn set_class_entity_permissions(
  327. origin,
  328. with_credential: Option<T::Credential>,
  329. class_id: ClassId,
  330. entity_permissions: EntityPermissions<T::Credential>
  331. ) -> dispatch::Result {
  332. let raw_origin = Self::ensure_root_or_signed(origin)?;
  333. Self::mutate_class_permissions(
  334. &raw_origin,
  335. with_credential,
  336. ClassPermissions::is_admin,
  337. class_id,
  338. |class_permissions| {
  339. class_permissions.entity_permissions = entity_permissions;
  340. Ok(())
  341. }
  342. )
  343. }
  344. fn set_class_entities_can_be_created(
  345. origin,
  346. with_credential: Option<T::Credential>,
  347. class_id: ClassId,
  348. can_be_created: bool
  349. ) -> dispatch::Result {
  350. let raw_origin = Self::ensure_root_or_signed(origin)?;
  351. Self::mutate_class_permissions(
  352. &raw_origin,
  353. with_credential,
  354. ClassPermissions::is_admin,
  355. class_id,
  356. |class_permissions| {
  357. class_permissions.entities_can_be_created = can_be_created;
  358. Ok(())
  359. }
  360. )
  361. }
  362. fn set_class_add_schemas_set(
  363. origin,
  364. with_credential: Option<T::Credential>,
  365. class_id: ClassId,
  366. credential_set: CredentialSet<T::Credential>
  367. ) -> dispatch::Result {
  368. let raw_origin = Self::ensure_root_or_signed(origin)?;
  369. Self::mutate_class_permissions(
  370. &raw_origin,
  371. with_credential,
  372. ClassPermissions::is_admin,
  373. class_id,
  374. |class_permissions| {
  375. class_permissions.add_schemas = credential_set;
  376. Ok(())
  377. }
  378. )
  379. }
  380. fn set_class_update_schemas_status_set(
  381. origin,
  382. with_credential: Option<T::Credential>,
  383. class_id: ClassId,
  384. credential_set: CredentialSet<T::Credential>
  385. ) -> dispatch::Result {
  386. let raw_origin = Self::ensure_root_or_signed(origin)?;
  387. Self::mutate_class_permissions(
  388. &raw_origin,
  389. with_credential,
  390. ClassPermissions::is_admin,
  391. class_id,
  392. |class_permissions| {
  393. class_permissions.update_schemas_status = credential_set;
  394. Ok(())
  395. }
  396. )
  397. }
  398. fn set_class_create_entities_set(
  399. origin,
  400. with_credential: Option<T::Credential>,
  401. class_id: ClassId,
  402. credential_set: CredentialSet<T::Credential>
  403. ) -> dispatch::Result {
  404. let raw_origin = Self::ensure_root_or_signed(origin)?;
  405. Self::mutate_class_permissions(
  406. &raw_origin,
  407. with_credential,
  408. ClassPermissions::is_admin,
  409. class_id,
  410. |class_permissions| {
  411. class_permissions.create_entities = credential_set;
  412. Ok(())
  413. }
  414. )
  415. }
  416. fn set_class_reference_constraint(
  417. origin,
  418. with_credential: Option<T::Credential>,
  419. class_id: ClassId,
  420. constraint: ReferenceConstraint<ClassId, u16>
  421. ) -> dispatch::Result {
  422. let raw_origin = Self::ensure_root_or_signed(origin)?;
  423. Self::mutate_class_permissions(
  424. &raw_origin,
  425. with_credential,
  426. ClassPermissions::is_admin,
  427. class_id,
  428. |class_permissions| {
  429. class_permissions.reference_constraint = constraint;
  430. Ok(())
  431. }
  432. )
  433. }
  434. // Setting a new maintainer for an entity may require having additional constraints.
  435. // So for now it is disabled.
  436. // pub fn set_entity_maintainer(
  437. // origin,
  438. // entity_id: EntityId,
  439. // new_maintainer: Option<T::Credential>
  440. // ) -> dispatch::Result {
  441. // ensure_root(origin)?;
  442. // // ensure entity exists in the versioned store
  443. // let _ = Self::get_class_id_by_entity_id(entity_id)?;
  444. // <EntityMaintainerByEntityId<T>>::mutate(entity_id, |maintainer| {
  445. // *maintainer = new_maintainer;
  446. // });
  447. // Ok(())
  448. // }
  449. // Permissioned proxy calls to versioned store
  450. pub fn create_class(
  451. origin,
  452. name: Vec<u8>,
  453. description: Vec<u8>,
  454. class_permissions: ClassPermissionsType<T>
  455. ) -> dispatch::Result {
  456. Self::ensure_can_create_class(origin)?;
  457. Self::ensure_class_name_is_valid(&name)?;
  458. Self::ensure_class_description_is_valid(&description)?;
  459. // is there a need to assert class_id is unique?
  460. let class_id = NextClassId::get();
  461. let class = Class::new(class_permissions, name, description);
  462. <ClassById<T>>::insert(&class_id, class);
  463. // Increment the next class id:
  464. NextClassId::mutate(|n| *n += 1);
  465. Ok(())
  466. }
  467. pub fn create_class_with_default_permissions(
  468. origin,
  469. name: Vec<u8>,
  470. description: Vec<u8>
  471. ) -> dispatch::Result {
  472. Self::create_class(origin, name, description, ClassPermissions::default())
  473. }
  474. pub fn add_class_schema(
  475. origin,
  476. with_credential: Option<T::Credential>,
  477. class_id: ClassId,
  478. existing_properties: Vec<u16>,
  479. new_properties: Vec<Property>
  480. ) -> dispatch::Result {
  481. let raw_origin = Self::ensure_root_or_signed(origin)?;
  482. Self::if_class_permissions_satisfied(
  483. &raw_origin,
  484. with_credential,
  485. None,
  486. ClassPermissions::can_add_class_schema,
  487. class_id,
  488. |_class_permissions, _access_level| {
  489. // If a new property points at another class,
  490. // at this point we don't enforce anything about reference constraints
  491. // because of the chicken and egg problem. Instead enforcement is done
  492. // at the time of creating an entity.
  493. let _schema_index = Self::append_class_schema(class_id, existing_properties, new_properties)?;
  494. Ok(())
  495. }
  496. )
  497. }
  498. pub fn update_class_schema_status(
  499. origin,
  500. with_credential: Option<T::Credential>,
  501. class_id: ClassId,
  502. schema_id: u16, // Do not type alias u16!! - u16,
  503. is_active: bool
  504. ) -> dispatch::Result {
  505. let raw_origin = Self::ensure_root_or_signed(origin)?;
  506. Self::if_class_permissions_satisfied(
  507. &raw_origin,
  508. with_credential,
  509. None,
  510. ClassPermissions::can_update_schema_status,
  511. class_id,
  512. |_class_permissions, _access_level| {
  513. // If a new property points at another class,
  514. // at this point we don't enforce anything about reference constraints
  515. // because of the chicken and egg problem. Instead enforcement is done
  516. // at the time of creating an entity.
  517. let _schema_index = Self::complete_class_schema_status_update(class_id, schema_id, is_active)?;
  518. Ok(())
  519. }
  520. )
  521. }
  522. /// Creates a new entity of type class_id. The maintainer is set to be either None if the origin is root, or the provided credential
  523. /// associated with signer.
  524. pub fn create_entity(
  525. origin,
  526. with_credential: Option<T::Credential>,
  527. class_id: ClassId
  528. ) -> dispatch::Result {
  529. let raw_origin = Self::ensure_root_or_signed(origin)?;
  530. let _entity_id = Self::do_create_entity(&raw_origin, with_credential, class_id)?;
  531. Ok(())
  532. }
  533. pub fn add_schema_support_to_entity(
  534. origin,
  535. with_credential: Option<T::Credential>,
  536. as_entity_maintainer: bool,
  537. entity_id: EntityId,
  538. schema_id: u16, // Do not type alias u16!! - u16,
  539. property_values: BTreeMap<u16, PropertyValue>
  540. ) -> dispatch::Result {
  541. let raw_origin = Self::ensure_root_or_signed(origin)?;
  542. Self::do_add_schema_support_to_entity(&raw_origin, with_credential, as_entity_maintainer, entity_id, schema_id, property_values)
  543. }
  544. pub fn update_entity_property_values(
  545. origin,
  546. with_credential: Option<T::Credential>,
  547. as_entity_maintainer: bool,
  548. entity_id: EntityId,
  549. property_values: BTreeMap<u16, PropertyValue>
  550. ) -> dispatch::Result {
  551. let raw_origin = Self::ensure_root_or_signed(origin)?;
  552. Self::do_update_entity_property_values(&raw_origin, with_credential, as_entity_maintainer, entity_id, property_values)
  553. }
  554. pub fn transaction(origin, operations: Vec<Operation<T::Credential>>) -> dispatch::Result {
  555. // This map holds the EntityId of the entity created as a result of executing a CreateEntity Operation
  556. // keyed by the indexed of the operation, in the operations vector.
  557. let mut entity_created_in_operation: BTreeMap<usize, EntityId> = BTreeMap::new();
  558. let raw_origin = Self::ensure_root_or_signed(origin)?;
  559. for (op_index, operation) in operations.into_iter().enumerate() {
  560. match operation.operation_type {
  561. OperationType::CreateEntity(create_entity_operation) => {
  562. let entity_id = Self::do_create_entity(&raw_origin, operation.with_credential, create_entity_operation.class_id)?;
  563. entity_created_in_operation.insert(op_index, entity_id);
  564. },
  565. OperationType::UpdatePropertyValues(update_property_values_operation) => {
  566. let entity_id = operations::parametrized_entity_to_entity_id(&entity_created_in_operation, update_property_values_operation.entity_id)?;
  567. let property_values = operations::parametrized_property_values_to_property_values(&entity_created_in_operation, update_property_values_operation.new_parametrized_property_values)?;
  568. Self::do_update_entity_property_values(&raw_origin, operation.with_credential, operation.as_entity_maintainer, entity_id, property_values)?;
  569. },
  570. OperationType::AddSchemaSupportToEntity(add_schema_support_to_entity_operation) => {
  571. let entity_id = operations::parametrized_entity_to_entity_id(&entity_created_in_operation, add_schema_support_to_entity_operation.entity_id)?;
  572. let schema_id = add_schema_support_to_entity_operation.schema_id;
  573. let property_values = operations::parametrized_property_values_to_property_values(&entity_created_in_operation, add_schema_support_to_entity_operation.parametrized_property_values)?;
  574. Self::do_add_schema_support_to_entity(&raw_origin, operation.with_credential, operation.as_entity_maintainer, entity_id, schema_id, property_values)?;
  575. }
  576. }
  577. }
  578. Ok(())
  579. }
  580. }
  581. }
  582. impl<T: Trait> Module<T> {
  583. fn ensure_root_or_signed(
  584. origin: T::Origin,
  585. ) -> Result<system::RawOrigin<T::AccountId>, &'static str> {
  586. match origin.into() {
  587. Ok(system::RawOrigin::Root) => Ok(system::RawOrigin::Root),
  588. Ok(system::RawOrigin::Signed(account_id)) => Ok(system::RawOrigin::Signed(account_id)),
  589. _ => Err("BadOrigin:ExpectedRootOrSigned"),
  590. }
  591. }
  592. fn ensure_can_create_class(origin: T::Origin) -> Result<(), &'static str> {
  593. let raw_origin = Self::ensure_root_or_signed(origin)?;
  594. let can_create_class = match raw_origin {
  595. system::RawOrigin::Root => true,
  596. system::RawOrigin::Signed(sender) => {
  597. T::CreateClassPermissionsChecker::account_can_create_class_permissions(&sender)
  598. }
  599. _ => false,
  600. };
  601. ensure!(can_create_class, "NotPermittedToCreateClass");
  602. Ok(())
  603. }
  604. fn do_create_entity(
  605. raw_origin: &system::RawOrigin<T::AccountId>,
  606. with_credential: Option<T::Credential>,
  607. class_id: ClassId,
  608. ) -> Result<EntityId, &'static str> {
  609. Self::if_class_permissions_satisfied(
  610. raw_origin,
  611. with_credential,
  612. None,
  613. ClassPermissions::can_create_entity,
  614. class_id,
  615. |_class_permissions, access_level| {
  616. let entity_id = Self::perform_entity_creation(class_id);
  617. // Note: mutating value to None is equivalient to removing the value from storage map
  618. <EntityMaintainerByEntityId<T>>::mutate(
  619. entity_id,
  620. |maintainer| match access_level {
  621. AccessLevel::System => *maintainer = None,
  622. AccessLevel::Credential(credential) => *maintainer = Some(*credential),
  623. _ => *maintainer = None,
  624. },
  625. );
  626. Ok(entity_id)
  627. },
  628. )
  629. }
  630. fn perform_entity_creation(class_id: ClassId) -> EntityId {
  631. let entity_id = NextEntityId::get();
  632. let new_entity = Entity {
  633. class_id,
  634. supported_schemas: BTreeSet::new(),
  635. values: BTreeMap::new(),
  636. };
  637. // Save newly created entity:
  638. EntityById::insert(entity_id, new_entity);
  639. // Increment the next entity id:
  640. NextEntityId::mutate(|n| *n += 1);
  641. entity_id
  642. }
  643. fn do_update_entity_property_values(
  644. raw_origin: &system::RawOrigin<T::AccountId>,
  645. with_credential: Option<T::Credential>,
  646. as_entity_maintainer: bool,
  647. entity_id: EntityId,
  648. property_values: BTreeMap<u16, PropertyValue>,
  649. ) -> dispatch::Result {
  650. let class_id = Self::get_class_id_by_entity_id(entity_id)?;
  651. Self::ensure_internal_property_values_permitted(class_id, &property_values)?;
  652. let as_entity_maintainer = if as_entity_maintainer {
  653. Some(entity_id)
  654. } else {
  655. None
  656. };
  657. Self::if_class_permissions_satisfied(
  658. raw_origin,
  659. with_credential,
  660. as_entity_maintainer,
  661. ClassPermissions::can_update_entity,
  662. class_id,
  663. |_class_permissions, _access_level| {
  664. Self::complete_entity_property_values_update(entity_id, property_values)
  665. },
  666. )
  667. }
  668. pub fn complete_class_schema_status_update(
  669. class_id: ClassId,
  670. schema_id: u16, // Do not type alias u16!! - u16,
  671. schema_status: bool,
  672. ) -> dispatch::Result {
  673. // Check that schema_id is a valid index of class schemas vector:
  674. Self::ensure_class_schema_id_exists(&Self::class_by_id(class_id), schema_id)?;
  675. <ClassById<T>>::mutate(class_id, |class| {
  676. class.update_schema_status(schema_id, schema_status)
  677. });
  678. Ok(())
  679. }
  680. pub fn complete_entity_property_values_update(
  681. entity_id: EntityId,
  682. new_property_values: BTreeMap<u16, PropertyValue>,
  683. ) -> dispatch::Result {
  684. Self::ensure_known_entity_id(&entity_id)?;
  685. let (entity, class) = Self::get_entity_and_class(entity_id);
  686. // Get current property values of an entity as a mutable vector,
  687. // so we can update them if new values provided present in new_property_values.
  688. let mut updated_values = entity.values;
  689. let mut updates_count = 0;
  690. // Iterate over a vector of new values and update corresponding properties
  691. // of this entity if new values are valid.
  692. for (id, new_value) in new_property_values.iter() {
  693. // Try to find a current property value in the entity
  694. // by matching its id to the id of a property with an updated value.
  695. if let Some(current_prop_value) = updated_values.get_mut(id) {
  696. // Get class-level information about this property
  697. let class_prop = &class.properties[*id as usize];
  698. // Validate a new property value against the type of this property
  699. // and check any additional constraints like the length of a vector
  700. // if it's a vector property or the length of a text if it's a text property.
  701. Self::ensure_property_value_is_valid(new_value, class_prop)?;
  702. // Update a current prop value in a mutable vector, if a new value is valid.
  703. *current_prop_value = new_value.to_owned();
  704. updates_count += 1;
  705. } else {
  706. // Throw an error if a property was not found on entity
  707. // by an in-class index of a property update.
  708. return Err(ERROR_UNKNOWN_ENTITY_PROP_ID);
  709. }
  710. }
  711. // If at least one of the entity property values should be update:
  712. if updates_count > 0 {
  713. EntityById::mutate(entity_id, |entity| {
  714. entity.values = updated_values;
  715. });
  716. }
  717. Ok(())
  718. }
  719. fn do_add_schema_support_to_entity(
  720. raw_origin: &system::RawOrigin<T::AccountId>,
  721. with_credential: Option<T::Credential>,
  722. as_entity_maintainer: bool,
  723. entity_id: EntityId,
  724. schema_id: u16,
  725. property_values: BTreeMap<u16, PropertyValue>,
  726. ) -> dispatch::Result {
  727. // class id of the entity being updated
  728. let class_id = Self::get_class_id_by_entity_id(entity_id)?;
  729. Self::ensure_internal_property_values_permitted(class_id, &property_values)?;
  730. let as_entity_maintainer = if as_entity_maintainer {
  731. Some(entity_id)
  732. } else {
  733. None
  734. };
  735. Self::if_class_permissions_satisfied(
  736. raw_origin,
  737. with_credential,
  738. as_entity_maintainer,
  739. ClassPermissions::can_update_entity,
  740. class_id,
  741. |_class_permissions, _access_level| {
  742. Self::add_entity_schema_support(entity_id, schema_id, property_values)
  743. },
  744. )
  745. }
  746. /// Derives the AccessLevel the caller is attempting to act with.
  747. /// It expects only signed or root origin.
  748. fn derive_access_level(
  749. raw_origin: &system::RawOrigin<T::AccountId>,
  750. with_credential: Option<T::Credential>,
  751. as_entity_maintainer: Option<EntityId>,
  752. ) -> Result<AccessLevel<T::Credential>, &'static str> {
  753. match raw_origin {
  754. system::RawOrigin::Root => Ok(AccessLevel::System),
  755. system::RawOrigin::Signed(account_id) => {
  756. if let Some(credential) = with_credential {
  757. if T::CredentialChecker::account_has_credential(&account_id, credential) {
  758. if let Some(entity_id) = as_entity_maintainer {
  759. // is entity maintained by system
  760. ensure!(
  761. <EntityMaintainerByEntityId<T>>::exists(entity_id),
  762. "NotEnityMaintainer"
  763. );
  764. // ensure entity maintainer matches
  765. match Self::entity_maintainer_by_entity_id(entity_id) {
  766. Some(maintainer_credential)
  767. if credential == maintainer_credential =>
  768. {
  769. Ok(AccessLevel::EntityMaintainer)
  770. }
  771. _ => Err("NotEnityMaintainer"),
  772. }
  773. } else {
  774. Ok(AccessLevel::Credential(credential))
  775. }
  776. } else {
  777. Err("OriginCannotActWithRequestedCredential")
  778. }
  779. } else {
  780. Ok(AccessLevel::Unspecified)
  781. }
  782. }
  783. _ => Err("BadOrigin:ExpectedRootOrSigned"),
  784. }
  785. }
  786. /// Returns the stored class if exist, error otherwise.
  787. fn ensure_class_exists(class_id: ClassId) -> Result<Class<T>, &'static str> {
  788. ensure!(<ClassById<T>>::exists(class_id), ERROR_CLASS_NOT_FOUND);
  789. Ok(Self::class_by_id(class_id))
  790. }
  791. /// Derives the access level of the caller.
  792. /// If the predicate passes, the mutate method is invoked.
  793. fn mutate_class_permissions<Predicate, Mutate>(
  794. raw_origin: &system::RawOrigin<T::AccountId>,
  795. with_credential: Option<T::Credential>,
  796. // predicate to test
  797. predicate: Predicate,
  798. // class permissions to perform mutation on if it exists
  799. class_id: ClassId,
  800. // actual mutation to apply.
  801. mutate: Mutate,
  802. ) -> dispatch::Result
  803. where
  804. Predicate:
  805. FnOnce(&ClassPermissionsType<T>, &AccessLevel<T::Credential>) -> dispatch::Result,
  806. Mutate: FnOnce(&mut ClassPermissionsType<T>) -> dispatch::Result,
  807. {
  808. let access_level = Self::derive_access_level(raw_origin, with_credential, None)?;
  809. let class = Self::ensure_class_exists(class_id)?;
  810. predicate(class.get_permissions(), &access_level)?;
  811. <ClassById<T>>::mutate(class_id, |inner_class| {
  812. //It is safe to not check for an error here, as result always be Ok(())
  813. let _ = mutate(inner_class.get_permissions_mut());
  814. // Refresh last permissions update block number.
  815. inner_class.refresh_last_permissions_update();
  816. });
  817. Ok(())
  818. }
  819. fn is_system(
  820. _: &ClassPermissionsType<T>,
  821. access_level: &AccessLevel<T::Credential>,
  822. ) -> dispatch::Result {
  823. if *access_level == AccessLevel::System {
  824. Ok(())
  825. } else {
  826. Err("NotRootOrigin")
  827. }
  828. }
  829. /// Derives the access level of the caller.
  830. /// If the peridcate passes the callback is invoked. Returns result of the callback
  831. /// or error from failed predicate.
  832. fn if_class_permissions_satisfied<Predicate, Callback, R>(
  833. raw_origin: &system::RawOrigin<T::AccountId>,
  834. with_credential: Option<T::Credential>,
  835. as_entity_maintainer: Option<EntityId>,
  836. // predicate to test
  837. predicate: Predicate,
  838. // class permissions to test
  839. class_id: ClassId,
  840. // callback to invoke if predicate passes
  841. callback: Callback,
  842. ) -> Result<R, &'static str>
  843. where
  844. Predicate:
  845. FnOnce(&ClassPermissionsType<T>, &AccessLevel<T::Credential>) -> dispatch::Result,
  846. Callback: FnOnce(
  847. &ClassPermissionsType<T>,
  848. &AccessLevel<T::Credential>,
  849. ) -> Result<R, &'static str>,
  850. {
  851. let access_level =
  852. Self::derive_access_level(raw_origin, with_credential, as_entity_maintainer)?;
  853. let class = Self::ensure_class_exists(class_id)?;
  854. let class_permissions = class.get_permissions();
  855. predicate(class_permissions, &access_level)?;
  856. callback(class_permissions, &access_level)
  857. }
  858. fn get_class_id_by_entity_id(entity_id: EntityId) -> Result<ClassId, &'static str> {
  859. // use a utility method on versioned_store module
  860. ensure!(EntityById::exists(entity_id), "EntityNotFound");
  861. let entity = Self::entity_by_id(entity_id);
  862. Ok(entity.class_id)
  863. }
  864. // Ensures property_values of type Internal that point to a class,
  865. // the target entity and class exists and constraint allows it.
  866. fn ensure_internal_property_values_permitted(
  867. source_class_id: ClassId,
  868. property_values: &BTreeMap<u16, PropertyValue>,
  869. ) -> dispatch::Result {
  870. for (in_class_index, property_value) in property_values.iter() {
  871. if let PropertyValue::Reference(ref target_entity_id) = property_value {
  872. // get the class permissions for target class
  873. let target_class_id = Self::get_class_id_by_entity_id(*target_entity_id)?;
  874. // assert class permissions exists for target class
  875. let class = Self::class_by_id(target_class_id);
  876. // ensure internal reference is permitted
  877. match &class.get_permissions().reference_constraint {
  878. ReferenceConstraint::NoConstraint => Ok(()),
  879. ReferenceConstraint::NoReferencingAllowed => {
  880. Err("EntityCannotReferenceTargetEntity")
  881. }
  882. ReferenceConstraint::Restricted(permitted_properties) => {
  883. if permitted_properties.contains(&PropertyOfClass {
  884. class_id: source_class_id,
  885. property_index: *in_class_index,
  886. }) {
  887. Ok(())
  888. } else {
  889. Err("EntityCannotReferenceTargetEntity")
  890. }
  891. }
  892. }?;
  893. }
  894. }
  895. // if we reach here all Internal properties have passed the constraint check
  896. Ok(())
  897. }
  898. /// Returns an index of a newly added class schema on success.
  899. pub fn append_class_schema(
  900. class_id: ClassId,
  901. existing_properties: Vec<u16>,
  902. new_properties: Vec<Property>,
  903. ) -> Result<u16, &'static str> {
  904. Self::ensure_known_class_id(&class_id)?;
  905. let non_empty_schema = !existing_properties.is_empty() || !new_properties.is_empty();
  906. ensure!(non_empty_schema, ERROR_NO_PROPS_IN_CLASS_SCHEMA);
  907. let class = <ClassById<T>>::get(class_id);
  908. // TODO Use BTreeSet for prop unique names when switched to Substrate 2.
  909. // There is no support for BTreeSet in Substrate 1 runtime.
  910. // use rstd::collections::btree_set::BTreeSet;
  911. let mut unique_prop_names = BTreeSet::new();
  912. for prop in class.properties.iter() {
  913. unique_prop_names.insert(prop.name.clone());
  914. }
  915. for prop in new_properties.iter() {
  916. Self::ensure_property_name_is_valid(&prop.name)?;
  917. Self::ensure_property_description_is_valid(&prop.description)?;
  918. // Check that the name of a new property is unique within its class.
  919. ensure!(
  920. !unique_prop_names.contains(&prop.name),
  921. ERROR_PROP_NAME_NOT_UNIQUE_IN_CLASS
  922. );
  923. unique_prop_names.insert(prop.name.clone());
  924. }
  925. // Check that existing props are valid indices of class properties vector:
  926. let has_unknown_props = existing_properties
  927. .iter()
  928. .any(|&prop_id| prop_id >= class.properties.len() as u16);
  929. ensure!(
  930. !has_unknown_props,
  931. ERROR_CLASS_SCHEMA_REFERS_UNKNOWN_PROP_INDEX
  932. );
  933. // Check validity of Internal(ClassId) for new_properties.
  934. let has_unknown_internal_id = new_properties.iter().any(|prop| match prop.prop_type {
  935. PropertyType::Reference(other_class_id) => !<ClassById<T>>::exists(other_class_id),
  936. _ => false,
  937. });
  938. ensure!(
  939. !has_unknown_internal_id,
  940. ERROR_CLASS_SCHEMA_REFERS_UNKNOWN_INTERNAL_ID
  941. );
  942. // Use the current length of schemas in this class as an index
  943. // for the next schema that will be sent in a result of this function.
  944. let schema_idx = class.schemas.len() as u16;
  945. let mut schema = Schema::new(existing_properties);
  946. let mut updated_class_props = class.properties;
  947. new_properties.into_iter().for_each(|prop| {
  948. let prop_id = updated_class_props.len() as u16;
  949. updated_class_props.push(prop);
  950. schema.properties.push(prop_id);
  951. });
  952. <ClassById<T>>::mutate(class_id, |class| {
  953. class.properties = updated_class_props;
  954. class.schemas.push(schema);
  955. });
  956. Ok(schema_idx)
  957. }
  958. pub fn add_entity_schema_support(
  959. entity_id: EntityId,
  960. schema_id: u16,
  961. property_values: BTreeMap<u16, PropertyValue>,
  962. ) -> dispatch::Result {
  963. Self::ensure_known_entity_id(&entity_id)?;
  964. let (entity, class) = Self::get_entity_and_class(entity_id);
  965. // Check that schema_id is a valid index of class schemas vector:
  966. Self::ensure_class_schema_id_exists(&class, schema_id)?;
  967. // Ensure class schema is active
  968. Self::ensure_class_schema_is_active(&class, schema_id)?;
  969. // Check that schema id is not yet added to this entity:
  970. Self::ensure_schema_id_is_not_added(&entity, schema_id)?;
  971. let class_schema_opt = class.schemas.get(schema_id as usize);
  972. let schema_prop_ids = class_schema_opt.unwrap().properties.clone();
  973. let current_entity_values = entity.values.clone();
  974. let mut appended_entity_values = entity.values;
  975. for prop_id in schema_prop_ids.iter() {
  976. if current_entity_values.contains_key(prop_id) {
  977. // A property is already added to the entity and cannot be updated
  978. // while adding a schema support to this entity.
  979. continue;
  980. }
  981. let class_prop = &class.properties[*prop_id as usize];
  982. // If a value was not povided for the property of this schema:
  983. if let Some(new_value) = property_values.get(prop_id) {
  984. Self::ensure_property_value_is_valid(new_value, class_prop)?;
  985. appended_entity_values.insert(*prop_id, new_value.to_owned());
  986. } else {
  987. // All required prop values should be are provided
  988. if class_prop.required {
  989. return Err(ERROR_MISSING_REQUIRED_PROP);
  990. }
  991. // Add all missing non required schema prop values as PropertyValue::None
  992. else {
  993. appended_entity_values.insert(*prop_id, PropertyValue::Bool(false));
  994. }
  995. }
  996. }
  997. EntityById::mutate(entity_id, |entity| {
  998. // Add a new schema to the list of schemas supported by this entity.
  999. entity.supported_schemas.insert(schema_id);
  1000. // Update entity values only if new properties have been added.
  1001. if appended_entity_values.len() > entity.values.len() {
  1002. entity.values = appended_entity_values;
  1003. }
  1004. });
  1005. Ok(())
  1006. }
  1007. // Commented out for now <- requested by Bedeho.
  1008. // pub fn delete_entity(entity_id: EntityId) -> dispatch::Result {
  1009. // Self::ensure_known_entity_id(entity_id)?;
  1010. // let is_deleted = EntityById::get(entity_id).deleted;
  1011. // ensure!(!is_deleted, ERROR_ENTITY_ALREADY_DELETED);
  1012. // EntityById::mutate(entity_id, |x| {
  1013. // x.deleted = true;
  1014. // });
  1015. // Self::deposit_event(RawEvent::EntityDeleted(entity_id));
  1016. // Ok(())
  1017. // }
  1018. // Helper functions:
  1019. // ----------------------------------------------------------------
  1020. pub fn ensure_known_class_id(class_id: &ClassId) -> dispatch::Result {
  1021. ensure!(<ClassById<T>>::exists(class_id), ERROR_CLASS_NOT_FOUND);
  1022. Ok(())
  1023. }
  1024. pub fn ensure_known_entity_id(entity_id: &EntityId) -> dispatch::Result {
  1025. ensure!(EntityById::exists(entity_id), ERROR_ENTITY_NOT_FOUND);
  1026. Ok(())
  1027. }
  1028. pub fn ensure_class_schema_id_exists(class: &Class<T>, schema_id: u16) -> dispatch::Result {
  1029. ensure!(
  1030. schema_id < class.schemas.len() as u16,
  1031. ERROR_UNKNOWN_CLASS_SCHEMA_ID
  1032. );
  1033. Ok(())
  1034. }
  1035. pub fn ensure_class_schema_is_active(class: &Class<T>, schema_id: u16) -> dispatch::Result {
  1036. ensure!(
  1037. class.is_active_schema(schema_id),
  1038. ERROR_CLASS_SCHEMA_NOT_ACTIVE
  1039. );
  1040. Ok(())
  1041. }
  1042. pub fn ensure_schema_id_is_not_added(entity: &Entity, schema_id: u16) -> dispatch::Result {
  1043. let schema_not_added = !entity.supported_schemas.contains(&schema_id);
  1044. ensure!(schema_not_added, ERROR_SCHEMA_ALREADY_ADDED_TO_ENTITY);
  1045. Ok(())
  1046. }
  1047. pub fn ensure_valid_internal_prop(value: &PropertyValue, prop: &Property) -> dispatch::Result {
  1048. match (value, &prop.prop_type) {
  1049. (PV::Reference(entity_id), PT::Reference(class_id)) => {
  1050. Self::ensure_known_class_id(class_id)?;
  1051. Self::ensure_known_entity_id(entity_id)?;
  1052. let entity = Self::entity_by_id(entity_id);
  1053. ensure!(
  1054. entity.class_id == *class_id,
  1055. ERROR_INTERNAL_RPOP_DOES_NOT_MATCH_ITS_CLASS
  1056. );
  1057. Ok(())
  1058. }
  1059. _ => Ok(()),
  1060. }
  1061. }
  1062. pub fn is_unknown_internal_entity_id(id: PropertyValue) -> bool {
  1063. if let PropertyValue::Reference(entity_id) = id {
  1064. !EntityById::exists(entity_id)
  1065. } else {
  1066. false
  1067. }
  1068. }
  1069. pub fn get_entity_and_class(entity_id: EntityId) -> (Entity, Class<T>) {
  1070. let entity = EntityById::get(entity_id);
  1071. let class = ClassById::get(entity.class_id);
  1072. (entity, class)
  1073. }
  1074. pub fn ensure_property_value_is_valid(
  1075. value: &PropertyValue,
  1076. prop: &Property,
  1077. ) -> dispatch::Result {
  1078. Self::ensure_prop_value_matches_its_type(value, prop)?;
  1079. Self::ensure_valid_internal_prop(value, prop)?;
  1080. Self::validate_max_len_if_text_prop(value, prop)?;
  1081. Self::validate_max_len_if_vec_prop(value, prop)?;
  1082. Ok(())
  1083. }
  1084. pub fn validate_max_len_if_text_prop(
  1085. value: &PropertyValue,
  1086. prop: &Property,
  1087. ) -> dispatch::Result {
  1088. match (value, &prop.prop_type) {
  1089. (PV::Text(text), PT::Text(max_len)) => Self::validate_max_len_of_text(text, *max_len),
  1090. _ => Ok(()),
  1091. }
  1092. }
  1093. pub fn validate_max_len_of_text(text: &[u8], max_len: u16) -> dispatch::Result {
  1094. if text.len() <= max_len as usize {
  1095. Ok(())
  1096. } else {
  1097. Err(ERROR_TEXT_PROP_IS_TOO_LONG)
  1098. }
  1099. }
  1100. #[rustfmt::skip]
  1101. pub fn validate_max_len_if_vec_prop(
  1102. value: &PropertyValue,
  1103. prop: &Property,
  1104. ) -> dispatch::Result {
  1105. fn validate_slice_len<T>(vec: &[T], max_len: &u16) -> bool {
  1106. vec.len() <= *max_len as usize
  1107. }
  1108. let is_valid_len = match (value, &prop.prop_type) {
  1109. (PV::BoolVec(vec), PT::BoolVec(max_len)) => validate_slice_len(vec, max_len),
  1110. (PV::Uint16Vec(vec), PT::Uint16Vec(max_len)) => validate_slice_len(vec, max_len),
  1111. (PV::Uint32Vec(vec), PT::Uint32Vec(max_len)) => validate_slice_len(vec, max_len),
  1112. (PV::Uint64Vec(vec), PT::Uint64Vec(max_len)) => validate_slice_len(vec, max_len),
  1113. (PV::Int16Vec(vec), PT::Int16Vec(max_len)) => validate_slice_len(vec, max_len),
  1114. (PV::Int32Vec(vec), PT::Int32Vec(max_len)) => validate_slice_len(vec, max_len),
  1115. (PV::Int64Vec(vec), PT::Int64Vec(max_len)) => validate_slice_len(vec, max_len),
  1116. (PV::TextVec(vec), PT::TextVec(vec_max_len, text_max_len)) => {
  1117. if validate_slice_len(vec, vec_max_len) {
  1118. for text_item in vec.iter() {
  1119. Self::validate_max_len_of_text(text_item, *text_max_len)?;
  1120. }
  1121. true
  1122. } else {
  1123. false
  1124. }
  1125. },
  1126. (PV::ReferenceVec(vec), PT::ReferenceVec(vec_max_len, class_id)) => {
  1127. Self::ensure_known_class_id(class_id)?;
  1128. if validate_slice_len(vec, vec_max_len) {
  1129. for entity_id in vec.iter() {
  1130. Self::ensure_known_entity_id(entity_id)?;
  1131. let entity = Self::entity_by_id(entity_id);
  1132. ensure!(entity.class_id == *class_id, ERROR_INTERNAL_RPOP_DOES_NOT_MATCH_ITS_CLASS);
  1133. }
  1134. true
  1135. } else {
  1136. false
  1137. }
  1138. },
  1139. _ => true
  1140. };
  1141. if is_valid_len {
  1142. Ok(())
  1143. } else {
  1144. Err(ERROR_VEC_PROP_IS_TOO_LONG)
  1145. }
  1146. }
  1147. pub fn ensure_prop_value_matches_its_type(
  1148. value: &PropertyValue,
  1149. prop: &Property,
  1150. ) -> dispatch::Result {
  1151. if Self::does_prop_value_match_type(value, prop) {
  1152. Ok(())
  1153. } else {
  1154. Err(ERROR_PROP_VALUE_DONT_MATCH_TYPE)
  1155. }
  1156. }
  1157. #[rustfmt::skip]
  1158. pub fn does_prop_value_match_type(
  1159. value: &PropertyValue,
  1160. prop: &Property,
  1161. ) -> bool {
  1162. // A non required property can be updated to None:
  1163. if !prop.required && *value == PV::Bool(false) {
  1164. return true
  1165. }
  1166. match (value, &prop.prop_type) {
  1167. // Single values
  1168. (PV::Bool(_), PT::Bool) |
  1169. (PV::Uint16(_), PT::Uint16) |
  1170. (PV::Uint32(_), PT::Uint32) |
  1171. (PV::Uint64(_), PT::Uint64) |
  1172. (PV::Int16(_), PT::Int16) |
  1173. (PV::Int32(_), PT::Int32) |
  1174. (PV::Int64(_), PT::Int64) |
  1175. (PV::Text(_), PT::Text(_)) |
  1176. (PV::Reference(_), PT::Reference(_)) |
  1177. // Vectors:
  1178. (PV::BoolVec(_), PT::BoolVec(_)) |
  1179. (PV::Uint16Vec(_), PT::Uint16Vec(_)) |
  1180. (PV::Uint32Vec(_), PT::Uint32Vec(_)) |
  1181. (PV::Uint64Vec(_), PT::Uint64Vec(_)) |
  1182. (PV::Int16Vec(_), PT::Int16Vec(_)) |
  1183. (PV::Int32Vec(_), PT::Int32Vec(_)) |
  1184. (PV::Int64Vec(_), PT::Int64Vec(_)) |
  1185. (PV::TextVec(_), PT::TextVec(_, _)) |
  1186. (PV::ReferenceVec(_), PT::ReferenceVec(_, _)) => true,
  1187. // (PV::External(_), PT::External(_)) => true,
  1188. // (PV::ExternalVec(_), PT::ExternalVec(_, _)) => true,
  1189. _ => false,
  1190. }
  1191. }
  1192. pub fn ensure_property_name_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1193. T::PropertyNameConstraint::get().ensure_valid(
  1194. text.len(),
  1195. ERROR_PROPERTY_NAME_TOO_SHORT,
  1196. ERROR_PROPERTY_NAME_TOO_LONG,
  1197. )
  1198. }
  1199. pub fn ensure_property_description_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1200. T::PropertyDescriptionConstraint::get().ensure_valid(
  1201. text.len(),
  1202. ERROR_PROPERTY_DESCRIPTION_TOO_SHORT,
  1203. ERROR_PROPERTY_DESCRIPTION_TOO_LONG,
  1204. )
  1205. }
  1206. pub fn ensure_class_name_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1207. T::ClassNameConstraint::get().ensure_valid(
  1208. text.len(),
  1209. ERROR_CLASS_NAME_TOO_SHORT,
  1210. ERROR_CLASS_NAME_TOO_LONG,
  1211. )
  1212. }
  1213. pub fn ensure_class_description_is_valid(text: &Vec<u8>) -> dispatch::Result {
  1214. T::ClassDescriptionConstraint::get().ensure_valid(
  1215. text.len(),
  1216. ERROR_CLASS_DESCRIPTION_TOO_SHORT,
  1217. ERROR_CLASS_DESCRIPTION_TOO_LONG,
  1218. )
  1219. }
  1220. }