From 5ff65ddc4185ed89139263e14e9b966e8dcd0f88 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Tue, 26 Apr 2022 09:03:39 -0300 Subject: [PATCH 01/15] Added nft pagination --- candid/nft.did | 2 ++ registries/nft/src/common_types.rs | 7 +++++++ registries/nft/src/nft.rs | 33 ++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/candid/nft.did b/candid/nft.did index 4ebd9f4..d6d31bb 100644 --- a/candid/nft.did +++ b/candid/nft.did @@ -40,5 +40,7 @@ service : { // Canister ethods "get_all" : () -> (vec nft_canister) query; + "get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: vec nft_canister; Err: operation_error }); + "add_admin" : (principal) -> (operation_response); } diff --git a/registries/nft/src/common_types.rs b/registries/nft/src/common_types.rs index 51bc09b..d9e8d14 100644 --- a/registries/nft/src/common_types.rs +++ b/registries/nft/src/common_types.rs @@ -28,6 +28,12 @@ pub struct NftCanister { pub details: Vec<(String, DetailValue)>, } +#[derive(CandidType, Clone, Debug, PartialEq)] +pub struct GetAllPaginatedResponse { + pub amount: usize, + pub nfts: Vec<&'static NftCanister>, +} + #[derive(CandidType, Debug, PartialEq, Deserialize, Clone)] pub enum OperationError { NotAuthorized, @@ -43,3 +49,4 @@ pub enum RegistryResponse { } pub const CANISTER_REGISTRY_ID: &'static str = "curr3-vaaaa-aaaah-abbdq-cai"; +pub const DEFAULT_LIMIT: usize = 20; diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index 6dfdb69..30bc20d 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -46,6 +46,27 @@ impl Registry { pub fn get_all(&self) -> Vec<&NftCanister> { self.0.values().collect() } + + pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { + + let nfts: Vec<&NftCanister> = self.0.values().collect(); + + if offset > nfts.len() { + return Err(OperationError::BadParameters); + } + + let mut limit = _limit; + + if offset + _limit > nfts.len() { + limit = nfts.len() - offset; + } + + return Ok(nfts[offset..(offset + limit)].to_vec()); + } + + pub fn get_amount(&self) -> usize { + return self.0.values().len(); + } } #[query] @@ -116,3 +137,15 @@ pub fn get_all() -> Vec<&'static NftCanister> { let db = ic::get_mut::(); db.get_all() } + +#[query] +pub fn get_all_paginated(offset: Option, limit: Option) -> Result, OperationError> { + let db = ic::get_mut::(); + let nfts = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; + let amount = db.get_amount(); + + return Ok(GetAllPaginatedResponse{ + nfts, + amount, + }); +} From 0c71e0be70a918629c26c16b82fbda0369255dcc Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 00:15:15 -0300 Subject: [PATCH 02/15] Added paginaton for the rest of the registries --- candid/nft.did | 7 +++- candid/registry.did | 6 ++++ candid/tokens.did | 6 ++++ .../canister_registry/src/common_types.rs | 7 ++++ registries/canister_registry/src/registry.rs | 33 +++++++++++++++++++ registries/nft/src/nft.rs | 2 +- registries/tokens/src/common_types.rs | 7 ++++ registries/tokens/src/tokens.rs | 33 +++++++++++++++++++ 8 files changed, 99 insertions(+), 2 deletions(-) diff --git a/candid/nft.did b/candid/nft.did index d6d31bb..d550877 100644 --- a/candid/nft.did +++ b/candid/nft.did @@ -19,6 +19,11 @@ type nft_canister = record { details : vec record { text; detail_value }; }; +type paginated_nft_canisters = record { + nfts: vec nft_canister; + amount: nat64; +}; + type operation_error = variant { NotAuthorized; NonExistentItem; @@ -40,7 +45,7 @@ service : { // Canister ethods "get_all" : () -> (vec nft_canister) query; - "get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: vec nft_canister; Err: operation_error }); + "get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: paginated_nft_canisters; Err: operation_error }); "add_admin" : (principal) -> (operation_response); } diff --git a/candid/registry.did b/candid/registry.did index b3c291a..988d620 100644 --- a/candid/registry.did +++ b/candid/registry.did @@ -19,6 +19,11 @@ type canister_metadata = record { details : vec record { text; detail_value }; }; +type paginated_canister_metadata = record { + canisters: vec canister_metadata; + amount: nat64; +}; + type operation_error = variant { NotAuthorized; BadParameters; @@ -38,6 +43,7 @@ service : { "add" : (canister_metadata) -> (operation_response); "remove" : (principal) -> (operation_response); "get_all" : () -> (vec canister_metadata) query; + "get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: paginated_canister_metadata; Err: operation_error }); "add_admin" : (principal) -> (operation_response); } diff --git a/candid/tokens.did b/candid/tokens.did index 068da5f..3478cd7 100644 --- a/candid/tokens.did +++ b/candid/tokens.did @@ -19,6 +19,11 @@ type token = record { details : vec record { text; detail_value } }; +type paginated_tokens = record { + tokens: vec token; + amount: nat64; +}; + type operation_error = variant { NotAuthorized; NonExistentItem; @@ -40,5 +45,6 @@ service : { // Canister methods "get_all" : () -> (vec token) query; + "get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: paginated_tokens; Err: operation_error }); "add_admin" : (principal) -> (operation_response); } diff --git a/registries/canister_registry/src/common_types.rs b/registries/canister_registry/src/common_types.rs index 01dae48..e3e280d 100644 --- a/registries/canister_registry/src/common_types.rs +++ b/registries/canister_registry/src/common_types.rs @@ -19,6 +19,12 @@ pub struct CanisterMetadata { pub details: Vec<(String, DetailValue)>, } +#[derive(CandidType, Clone, Debug, PartialEq)] +pub struct GetAllPaginatedResponse { + pub amount: usize, + pub canisters: Vec<&'static CanisterMetadata>, +} + #[derive(CandidType, Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum DetailValue { True, @@ -35,3 +41,4 @@ pub enum DetailValue { pub const DESCRIPTION_LIMIT: usize = 1200; pub const NAME_LIMIT: usize = 24; +pub const DEFAULT_LIMIT: usize = 20; diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index fde7a3b..187257c 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -46,6 +46,27 @@ impl CanisterDB { pub fn get_all(&self) -> Vec<&CanisterMetadata> { self.0.values().collect() } + + pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, Failure> { + + let canisters: Vec<&CanisterMetadata> = self.0.values().collect(); + + if offset > canisters.len() { + return Err(Failure::BadParameters); + } + + let mut limit = _limit; + + if offset + _limit > canisters.len() { + limit = canisters.len() - offset; + } + + return Ok(canisters[offset..(offset + limit)].to_vec()); + } + + pub fn get_amount(&self) -> usize { + return self.0.values().len(); + } } #[init] @@ -94,3 +115,15 @@ pub fn get_all() -> Vec<&'static CanisterMetadata> { let canister_db = ic::get_mut::(); canister_db.get_all() } + +#[query] +pub fn get_all_paginated(offset: Option, limit: Option) -> Result { + let db = ic::get_mut::(); + let canisters = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; + let amount = db.get_amount(); + + return Ok(GetAllPaginatedResponse{ + canisters, + amount, + }); +} \ No newline at end of file diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index 30bc20d..024af0f 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -139,7 +139,7 @@ pub fn get_all() -> Vec<&'static NftCanister> { } #[query] -pub fn get_all_paginated(offset: Option, limit: Option) -> Result, OperationError> { +pub fn get_all_paginated(offset: Option, limit: Option) -> Result { let db = ic::get_mut::(); let nfts = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; let amount = db.get_amount(); diff --git a/registries/tokens/src/common_types.rs b/registries/tokens/src/common_types.rs index 32cab02..71f85fe 100644 --- a/registries/tokens/src/common_types.rs +++ b/registries/tokens/src/common_types.rs @@ -25,6 +25,12 @@ pub struct Token { pub details: Vec<(String, DetailValue)>, } +#[derive(CandidType, Clone, Debug, PartialEq)] +pub struct GetAllPaginatedResponse { + pub amount: usize, + pub tokens: Vec<&'static Token>, +} + #[derive(CandidType, Debug, Deserialize)] pub enum OperationError { NotAuthorized, @@ -40,3 +46,4 @@ pub enum RegistryResponse { } pub const CANISTER_REGISTRY_ID: &'static str = "curr3-vaaaa-aaaah-abbdq-cai"; +pub const DEFAULT_LIMIT: usize = 20; diff --git a/registries/tokens/src/tokens.rs b/registries/tokens/src/tokens.rs index 2c1ee6b..1551d93 100644 --- a/registries/tokens/src/tokens.rs +++ b/registries/tokens/src/tokens.rs @@ -48,6 +48,27 @@ impl TokenRegistry { pub fn get_all(&self) -> Vec<&Token> { self.0.values().collect() } + + pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { + + let tokens: Vec<&Token> = self.0.values().collect(); + + if offset > tokens.len() { + return Err(OperationError::BadParameters); + } + + let mut limit = _limit; + + if offset + _limit > tokens.len() { + limit = tokens.len() - offset; + } + + return Ok(tokens[offset..(offset + limit)].to_vec()); + } + + pub fn get_amount(&self) -> usize { + return self.0.values().len(); + } } #[init] @@ -135,3 +156,15 @@ pub fn get_all() -> Vec<&'static Token> { let db = ic::get_mut::(); db.get_all() } + +#[query] +pub fn get_all_paginated(offset: Option, limit: Option) -> Result { + let db = ic::get_mut::(); + let tokens = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; + let amount = db.get_amount(); + + return Ok(GetAllPaginatedResponse{ + tokens, + amount, + }); +} From 2e450212739c2f260c23be8c4d220ddbeb400039 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 22:03:46 -0300 Subject: [PATCH 03/15] Normalized error types to OperationError (previously Failure) --- registries/address_book/src/address_book.rs | 30 +++++++++---------- registries/address_book/src/common_types.rs | 2 +- registries/address_book/src/tests.rs | 6 ++-- .../canister_registry/src/common_types.rs | 2 +- registries/canister_registry/src/registry.rs | 24 +++++++-------- registries/canister_registry/src/tests.rs | 14 ++++----- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/registries/address_book/src/address_book.rs b/registries/address_book/src/address_book.rs index 304d227..102397a 100644 --- a/registries/address_book/src/address_book.rs +++ b/registries/address_book/src/address_book.rs @@ -57,33 +57,33 @@ impl AddressBook { return result.0.is_some(); } - pub async fn validate_address_type(&mut self, address: AddressType) -> Result<(), Failure> { + pub async fn validate_address_type(&mut self, address: AddressType) -> Result<(), OperationError> { match address { AddressType::Icns(s) => match self.validate_icns(s).await { true => return Ok(()), - false => return Err(Failure::BadParameters), + false => return Err(OperationError::BadParameters), }, AddressType::AccountId(s) => match self.validate_account_id(s) { true => return Ok(()), - false => return Err(Failure::BadParameters), + false => return Err(OperationError::BadParameters), }, AddressType::PrincipalId(_s) => Ok(()), - _ => Err(Failure::BadParameters), + _ => Err(OperationError::BadParameters), } } - pub fn add(&mut self, account: Principal, address: Address) -> Result<(), Failure> { + pub fn add(&mut self, account: Principal, address: Address) -> Result<(), OperationError> { let pointer: Key = (account, address.name.clone()); self.0.insert(pointer.clone(), address); return Ok(()); } - pub fn remove(&mut self, account: Principal, canister_name: String) -> Result<(), Failure> { + pub fn remove(&mut self, account: Principal, canister_name: String) -> Result<(), OperationError> { let pointer: Key = (account, canister_name); if !self.0.contains_key(&pointer) { - return Err(Failure::NonExistentItem); + return Err(OperationError::NonExistentItem); } self.0.remove(&pointer); @@ -103,11 +103,11 @@ impl AddressBook { account: Principal, offset: usize, _limit: usize, - ) -> Result, Failure> { + ) -> Result, OperationError> { let mut limit = _limit; if offset >= limit { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } let start: Key = (account.clone(), String::new()); @@ -131,20 +131,20 @@ fn name() -> String { } #[update] -pub async fn add(address: Address) -> Result<(), Failure> { +pub async fn add(address: Address) -> Result<(), OperationError> { if &address.name.len() > &NAME_LIMIT { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } else if address.description.is_some() { let description = address.clone().description.unwrap(); if &description.len() > &DESCRIPTION_LIMIT { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } } else if address.emoji.is_some() { let emojis: Vec = address.clone().emoji.unwrap().chars().take(1).collect(); if !is_emoji(emojis[0]) { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } } @@ -159,7 +159,7 @@ pub async fn add(address: Address) -> Result<(), Failure> { } #[update] -pub fn remove(address_name: String) -> Result<(), Failure> { +pub fn remove(address_name: String) -> Result<(), OperationError> { let address_book = ic::get_mut::(); return address_book.remove(ic::caller(), address_name); } @@ -178,7 +178,7 @@ pub fn get_all() -> Vec<&'static Address> { pub fn get_all_paginated( offset: Option, limit: Option, -) -> Result, Failure> { +) -> Result, OperationError> { let address_book = ic::get_mut::(); let addresses = address_book .get_all_paginated( diff --git a/registries/address_book/src/common_types.rs b/registries/address_book/src/common_types.rs index c2a4bab..d805101 100644 --- a/registries/address_book/src/common_types.rs +++ b/registries/address_book/src/common_types.rs @@ -36,7 +36,7 @@ pub const ICNS_REGISTRY_PRINCIPAL_ID: &str = "e5kvl-zyaaa-aaaan-qabaq-cai"; pub const DEFAULT_LIMIT: usize = 20; #[derive(CandidType, Debug, PartialEq)] -pub enum Failure { +pub enum OperationError { NotAuthorized, BadParameters, NonExistentItem, diff --git a/registries/address_book/src/tests.rs b/registries/address_book/src/tests.rs index 82cc87c..9b9ac57 100644 --- a/registries/address_book/src/tests.rs +++ b/registries/address_book/src/tests.rs @@ -69,7 +69,7 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), Failure::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); } #[tokio::test] @@ -87,7 +87,7 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), Failure::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); } // #[tokio::test] @@ -105,7 +105,7 @@ mod tests { // let addition_result = add(address_info.clone()).await; // assert!(addition_result.is_err()); - // assert_eq!(addition_result.unwrap_err(), Failure::BadParameters); + // assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); // } #[tokio::test] diff --git a/registries/canister_registry/src/common_types.rs b/registries/canister_registry/src/common_types.rs index e3e280d..793ea03 100644 --- a/registries/canister_registry/src/common_types.rs +++ b/registries/canister_registry/src/common_types.rs @@ -2,7 +2,7 @@ use ic_kit::{candid::CandidType, Principal}; use serde::{Deserialize, Serialize}; #[derive(CandidType, Debug, PartialEq)] -pub enum Failure { +pub enum OperationError { NotAuthorized, BadParameters, NonExistentItem, diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index 187257c..da81e75 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -24,20 +24,20 @@ impl CanisterDB { self.0.get(&canister) } - pub fn add_canister(&mut self, metadata: CanisterMetadata) -> Result<(), Failure> { + pub fn add_canister(&mut self, metadata: CanisterMetadata) -> Result<(), OperationError> { let id: Principal = metadata.principal_id; self.0.insert(metadata.principal_id, metadata); if !self.0.contains_key(&id) { - return Err(Failure::Unknown(String::from( + return Err(OperationError::Unknown(String::from( "Something unexpected happend. Try again.", ))); } Ok(()) } - pub fn remove_canister(&mut self, canister: &Principal) -> Result<(), Failure> { + pub fn remove_canister(&mut self, canister: &Principal) -> Result<(), OperationError> { if !self.0.contains_key(canister) { - return Err(Failure::NonExistentItem); + return Err(OperationError::NonExistentItem); } self.0.remove(canister); Ok(()) @@ -47,12 +47,12 @@ impl CanisterDB { self.0.values().collect() } - pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, Failure> { + pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { let canisters: Vec<&CanisterMetadata> = self.0.values().collect(); if offset > canisters.len() { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } let mut limit = _limit; @@ -86,15 +86,15 @@ pub fn get(canister: Principal) -> Option<&'static CanisterMetadata> { } #[update] -pub fn add(metadata: CanisterMetadata) -> Result<(), Failure> { +pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { if !is_admin(&ic::caller()) { - return Err(Failure::NotAuthorized); + return Err(OperationError::NotAuthorized); } else if &metadata.name.len() > &NAME_LIMIT || &metadata.description.len() > &DESCRIPTION_LIMIT || !validate_url(&metadata.thumbnail) || !metadata.clone().frontend.map(validate_url).unwrap_or(true) { - return Err(Failure::BadParameters); + return Err(OperationError::BadParameters); } let canister_db = ic::get_mut::(); @@ -102,9 +102,9 @@ pub fn add(metadata: CanisterMetadata) -> Result<(), Failure> { } #[update] -pub fn remove(canister: Principal) -> Result<(), Failure> { +pub fn remove(canister: Principal) -> Result<(), OperationError> { if !is_admin(&ic::caller()) { - return Err(Failure::NotAuthorized); + return Err(OperationError::NotAuthorized); } let canister_db = ic::get_mut::(); canister_db.remove_canister(&canister) @@ -117,7 +117,7 @@ pub fn get_all() -> Vec<&'static CanisterMetadata> { } #[query] -pub fn get_all_paginated(offset: Option, limit: Option) -> Result { +pub fn get_all_paginated(offset: Option, limit: Option) -> Result { let db = ic::get_mut::(); let canisters = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; let amount = db.get_amount(); diff --git a/registries/canister_registry/src/tests.rs b/registries/canister_registry/src/tests.rs index c95f15c..ca7fd8e 100644 --- a/registries/canister_registry/src/tests.rs +++ b/registries/canister_registry/src/tests.rs @@ -128,7 +128,7 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), Failure::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); @@ -156,7 +156,7 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), Failure::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); @@ -186,7 +186,7 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), Failure::NotAuthorized); + assert_eq!(addition_result.unwrap_err(), OperationError::NotAuthorized); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); @@ -288,7 +288,7 @@ mod tests { let remove_result = remove(mock_principals::xtc()); assert!(remove_result.is_err()); - assert_eq!(remove_result.unwrap_err(), Failure::NonExistentItem); + assert_eq!(remove_result.unwrap_err(), OperationError::NonExistentItem); } #[test] @@ -318,7 +318,7 @@ mod tests { let remove_result = remove(mock_principals::xtc()); assert!(remove_result.is_err()); - assert_eq!(remove_result.unwrap_err(), Failure::NotAuthorized); + assert_eq!(remove_result.unwrap_err(), OperationError::NotAuthorized); } #[test] @@ -486,11 +486,11 @@ mod tests { // the canister should return an error if we try to remove a non-existent canister let remove_operation = remove(mock_principals::xtc()); - assert_eq!(remove_operation.err().unwrap(), Failure::NonExistentItem); + assert_eq!(remove_operation.err().unwrap(), OperationError::NonExistentItem); // Bob should not be able to remove a canister because he is not an admin ctx.update_caller(mock_principals::bob()); let remove_operation = remove(mock_principals::xtc()); - assert_eq!(remove_operation.err().unwrap(), Failure::NotAuthorized); + assert_eq!(remove_operation.err().unwrap(), OperationError::NotAuthorized); } } From af906b77de159fea8c8678528d949581c8e8f03a Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 22:30:51 -0300 Subject: [PATCH 04/15] Added specific BadParameters messages for canister registry --- .../canister_registry/src/common_types.rs | 2 +- .../canister_registry/src/management.rs | 10 ++++---- registries/canister_registry/src/registry.rs | 24 +++++++++++++------ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/registries/canister_registry/src/common_types.rs b/registries/canister_registry/src/common_types.rs index 793ea03..d498921 100644 --- a/registries/canister_registry/src/common_types.rs +++ b/registries/canister_registry/src/common_types.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; #[derive(CandidType, Debug, PartialEq)] pub enum OperationError { NotAuthorized, - BadParameters, + BadParameters(String), NonExistentItem, Unknown(String), } diff --git a/registries/canister_registry/src/management.rs b/registries/canister_registry/src/management.rs index 633758e..8c042ff 100644 --- a/registries/canister_registry/src/management.rs +++ b/registries/canister_registry/src/management.rs @@ -2,7 +2,7 @@ use ic_kit::ic; use ic_kit::macros::*; use ic_kit::Principal; -use crate::common_types::Failure; +use crate::common_types::OperationError; pub struct Admins(pub Vec); @@ -17,19 +17,19 @@ pub fn is_admin(account: &Principal) -> bool { } #[update] -pub fn add_admin(new_admin: Principal) -> Result<(), Failure> { +pub fn add_admin(new_admin: Principal) -> Result<(), OperationError> { if is_admin(&ic::caller()) { ic::get_mut::().0.push(new_admin); return Ok(()); } - Err(Failure::NotAuthorized) + Err(OperationError::NotAuthorized) } #[update] -pub fn remove_admin(admin: Principal) -> Result<(), Failure> { +pub fn remove_admin(admin: Principal) -> Result<(), OperationError> { if is_admin(&ic::caller()) { ic::get_mut::().0.retain(|x| *x != admin); return Ok(()); } - Err(Failure::NotAuthorized) + Err(OperationError::NotAuthorized) } diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index da81e75..d2c990b 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -52,7 +52,7 @@ impl CanisterDB { let canisters: Vec<&CanisterMetadata> = self.0.values().collect(); if offset > canisters.len() { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(String::from("Offset out of bound."))); } let mut limit = _limit; @@ -89,12 +89,22 @@ pub fn get(canister: Principal) -> Option<&'static CanisterMetadata> { pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { if !is_admin(&ic::caller()) { return Err(OperationError::NotAuthorized); - } else if &metadata.name.len() > &NAME_LIMIT - || &metadata.description.len() > &DESCRIPTION_LIMIT - || !validate_url(&metadata.thumbnail) - || !metadata.clone().frontend.map(validate_url).unwrap_or(true) - { - return Err(OperationError::BadParameters); + } + + if &metadata.name.len() > &NAME_LIMIT { + return Err(OperationError::BadParameters(format!("Name field has to be less than {} characters long", NAME_LIMIT))); + } + + if &metadata.description.len() > &DESCRIPTION_LIMIT { + return Err(OperationError::BadParameters(format!("Description field has to be less than {} characters long", DESCRIPTION_LIMIT))); + } + + if !validate_url(&metadata.thumbnail) { + return Err(OperationError::BadParameters(String::from("Thumbnail field has to be a url"))); + } + + if metadata.clone().frontend.is_some() && !validate_url(&metadata.frontend.unwrap()) { + return Err(OperationError::BadParameters(String::from("Frontend field has to be a url"))); } let canister_db = ic::get_mut::(); From 8f0d2dd426140df5a039348aef7a1a9f81c7fd6e Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 22:50:47 -0300 Subject: [PATCH 05/15] Added specific BadParameters messages for nft registry --- registries/canister_registry/src/registry.rs | 8 +- registries/nft/src/nft.rs | 102 +++++++++++-------- 2 files changed, 65 insertions(+), 45 deletions(-) diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index d2c990b..2b759c8 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -92,19 +92,19 @@ pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { } if &metadata.name.len() > &NAME_LIMIT { - return Err(OperationError::BadParameters(format!("Name field has to be less than {} characters long", NAME_LIMIT))); + return Err(OperationError::BadParameters(format!("Name field has to be less than {} characters long.", NAME_LIMIT))); } if &metadata.description.len() > &DESCRIPTION_LIMIT { - return Err(OperationError::BadParameters(format!("Description field has to be less than {} characters long", DESCRIPTION_LIMIT))); + return Err(OperationError::BadParameters(format!("Description field has to be less than {} characters long.", DESCRIPTION_LIMIT))); } if !validate_url(&metadata.thumbnail) { - return Err(OperationError::BadParameters(String::from("Thumbnail field has to be a url"))); + return Err(OperationError::BadParameters(String::from("Thumbnail field has to be a url."))); } if metadata.clone().frontend.is_some() && !validate_url(&metadata.frontend.unwrap()) { - return Err(OperationError::BadParameters(String::from("Frontend field has to be a url"))); + return Err(OperationError::BadParameters(String::from("Frontend field has to be a url."))); } let canister_db = ic::get_mut::(); diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index 024af0f..5d8d9c3 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -47,17 +47,20 @@ impl Registry { self.0.values().collect() } - pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { - + pub fn get_all_paginated( + &self, + offset: usize, + _limit: usize, + ) -> Result, OperationError> { let nfts: Vec<&NftCanister> = self.0.values().collect(); if offset > nfts.len() { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(String::from("Offset out of bound."))); } let mut limit = _limit; - if offset + _limit > nfts.len() { + if offset + _limit > nfts.len() { limit = nfts.len() - offset; } @@ -78,42 +81,59 @@ fn name() -> String { pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { if !is_admin(&ic::caller()) { return Err(OperationError::NotAuthorized); - } else if !validate_url(&canister_info.thumbnail) { - return Err(OperationError::BadParameters); - } else if canister_info.frontend.is_some() - && !validate_url(&canister_info.frontend.clone().unwrap()) - { - return Err(OperationError::BadParameters); - } else if canister_info.details[0].0 != String::from("standard") { - return Err(OperationError::BadParameters); - } else if canister_info.details.len() != 1 { - return Err(OperationError::BadParameters); } - let name = canister_info.name.clone(); - if name.len() <= NAME_LIMIT && &canister_info.description.len() <= &DESCRIPTION_LIMIT { - // Add the collection to the canister registry - let mut call_arg: NftCanister = canister_info.clone(); - call_arg.details = vec![("category".to_string(), DetailValue::Text("NFT".to_string()))]; - - let _registry_add_response: RegistryResponse = match ic::call( - Principal::from_str(CANISTER_REGISTRY_ID).unwrap(), - "add", - (call_arg,), - ) - .await - { - Ok((x,)) => x, - Err((_code, msg)) => { - return Err(OperationError::Unknown(msg)); - } - }; - - let db = ic::get_mut::(); - return db.add(canister_info); + if &canister_info.name.len() > &NAME_LIMIT { + return Err(OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ))); + } + + if &canister_info.description.len() > &DESCRIPTION_LIMIT { + return Err(OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ))); + } + + if !validate_url(&metadata.thumbnail) { + return Err(OperationError::BadParameters(String::from( + "Thumbnail field has to be a url.", + ))); + } + + if canister_info.clone().frontend.is_some() && !validate_url(&canister_info.frontend.unwrap()) { + return Err(OperationError::BadParameters(String::from( + "Frontend field has to be a url.", + ))); } - Err(OperationError::BadParameters) + if &canister_info.details[0].0 != String::from("standard") { + return Err(OperationError::BadParameters(String::from( + "First detail field has to be standard.", + ))); + } + + // Add the collection to the canister registry + let mut call_arg: NftCanister = canister_info.clone(); + call_arg.details = vec![("category".to_string(), DetailValue::Text("NFT".to_string()))]; + + let _registry_add_response: RegistryResponse = match ic::call( + Principal::from_str(CANISTER_REGISTRY_ID).unwrap(), + "add", + (call_arg,), + ) + .await + { + Ok((x,)) => x, + Err((_code, msg)) => { + return Err(OperationError::Unknown(msg)); + } + }; + + let db = ic::get_mut::(); + return db.add(canister_info); } #[update] @@ -139,13 +159,13 @@ pub fn get_all() -> Vec<&'static NftCanister> { } #[query] -pub fn get_all_paginated(offset: Option, limit: Option) -> Result { +pub fn get_all_paginated( + offset: Option, + limit: Option, +) -> Result { let db = ic::get_mut::(); let nfts = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; let amount = db.get_amount(); - return Ok(GetAllPaginatedResponse{ - nfts, - amount, - }); + return Ok(GetAllPaginatedResponse { nfts, amount }); } From 4a241fbcfed724005b4f26d12026a65fd82e3dea Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:11:31 -0300 Subject: [PATCH 06/15] Refactored params validation --- registries/address_book/src/address_book.rs | 11 ++- registries/canister_registry/src/registry.rs | 45 ++++++---- registries/canister_registry/src/tests.rs | 10 ++- registries/nft/src/common_types.rs | 2 +- registries/nft/src/nft.rs | 34 +++++--- registries/tokens/src/common_types.rs | 5 +- registries/tokens/src/tokens.rs | 91 ++++++++++++++------ 7 files changed, 140 insertions(+), 58 deletions(-) diff --git a/registries/address_book/src/address_book.rs b/registries/address_book/src/address_book.rs index 102397a..0cef6bf 100644 --- a/registries/address_book/src/address_book.rs +++ b/registries/address_book/src/address_book.rs @@ -57,7 +57,10 @@ impl AddressBook { return result.0.is_some(); } - pub async fn validate_address_type(&mut self, address: AddressType) -> Result<(), OperationError> { + pub async fn validate_address_type( + &mut self, + address: AddressType, + ) -> Result<(), OperationError> { match address { AddressType::Icns(s) => match self.validate_icns(s).await { true => return Ok(()), @@ -79,7 +82,11 @@ impl AddressBook { return Ok(()); } - pub fn remove(&mut self, account: Principal, canister_name: String) -> Result<(), OperationError> { + pub fn remove( + &mut self, + account: Principal, + canister_name: String, + ) -> Result<(), OperationError> { let pointer: Key = (account, canister_name); if !self.0.contains_key(&pointer) { diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index 2b759c8..84c22ae 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -47,17 +47,22 @@ impl CanisterDB { self.0.values().collect() } - pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { - + pub fn get_all_paginated( + &self, + offset: usize, + _limit: usize, + ) -> Result, OperationError> { let canisters: Vec<&CanisterMetadata> = self.0.values().collect(); if offset > canisters.len() { - return Err(OperationError::BadParameters(String::from("Offset out of bound."))); + return Err(OperationError::BadParameters(String::from( + "Offset out of bound.", + ))); } let mut limit = _limit; - if offset + _limit > canisters.len() { + if offset + _limit > canisters.len() { limit = canisters.len() - offset; } @@ -92,19 +97,29 @@ pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { } if &metadata.name.len() > &NAME_LIMIT { - return Err(OperationError::BadParameters(format!("Name field has to be less than {} characters long.", NAME_LIMIT))); + return Err(OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ))); } if &metadata.description.len() > &DESCRIPTION_LIMIT { - return Err(OperationError::BadParameters(format!("Description field has to be less than {} characters long.", DESCRIPTION_LIMIT))); + return Err(OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ))); } if !validate_url(&metadata.thumbnail) { - return Err(OperationError::BadParameters(String::from("Thumbnail field has to be a url."))); + return Err(OperationError::BadParameters(String::from( + "Thumbnail field has to be a url.", + ))); } - if metadata.clone().frontend.is_some() && !validate_url(&metadata.frontend.unwrap()) { - return Err(OperationError::BadParameters(String::from("Frontend field has to be a url."))); + if metadata.clone().frontend.is_some() && !validate_url(metadata.clone().frontend.unwrap()) { + return Err(OperationError::BadParameters(String::from( + "Frontend field has to be a url.", + ))); } let canister_db = ic::get_mut::(); @@ -127,13 +142,13 @@ pub fn get_all() -> Vec<&'static CanisterMetadata> { } #[query] -pub fn get_all_paginated(offset: Option, limit: Option) -> Result { +pub fn get_all_paginated( + offset: Option, + limit: Option, +) -> Result { let db = ic::get_mut::(); let canisters = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; let amount = db.get_amount(); - return Ok(GetAllPaginatedResponse{ - canisters, - amount, - }); -} \ No newline at end of file + return Ok(GetAllPaginatedResponse { canisters, amount }); +} diff --git a/registries/canister_registry/src/tests.rs b/registries/canister_registry/src/tests.rs index ca7fd8e..823775d 100644 --- a/registries/canister_registry/src/tests.rs +++ b/registries/canister_registry/src/tests.rs @@ -486,11 +486,17 @@ mod tests { // the canister should return an error if we try to remove a non-existent canister let remove_operation = remove(mock_principals::xtc()); - assert_eq!(remove_operation.err().unwrap(), OperationError::NonExistentItem); + assert_eq!( + remove_operation.err().unwrap(), + OperationError::NonExistentItem + ); // Bob should not be able to remove a canister because he is not an admin ctx.update_caller(mock_principals::bob()); let remove_operation = remove(mock_principals::xtc()); - assert_eq!(remove_operation.err().unwrap(), OperationError::NotAuthorized); + assert_eq!( + remove_operation.err().unwrap(), + OperationError::NotAuthorized + ); } } diff --git a/registries/nft/src/common_types.rs b/registries/nft/src/common_types.rs index d9e8d14..b272fc5 100644 --- a/registries/nft/src/common_types.rs +++ b/registries/nft/src/common_types.rs @@ -38,7 +38,7 @@ pub struct GetAllPaginatedResponse { pub enum OperationError { NotAuthorized, NonExistentItem, - BadParameters, + BadParameters(String), Unknown(String), } diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index 5d8d9c3..a52d025 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -55,7 +55,9 @@ impl Registry { let nfts: Vec<&NftCanister> = self.0.values().collect(); if offset > nfts.len() { - return Err(OperationError::BadParameters(String::from("Offset out of bound."))); + return Err(OperationError::BadParameters(String::from( + "Offset out of bound.", + ))); } let mut limit = _limit; @@ -84,32 +86,40 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { } if &canister_info.name.len() > &NAME_LIMIT { - return Err(OperationError::BadParameters(format!( - "Name field has to be less than {} characters long.", - NAME_LIMIT - ))); + return Err(OperationError::BadParameters( + format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ) + .to_string(), + )); } if &canister_info.description.len() > &DESCRIPTION_LIMIT { - return Err(OperationError::BadParameters(format!( - "Description field has to be less than {} characters long.", - DESCRIPTION_LIMIT - ))); + return Err(OperationError::BadParameters( + format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ) + .to_string(), + )); } - if !validate_url(&metadata.thumbnail) { + if !validate_url(&canister_info.thumbnail) { return Err(OperationError::BadParameters(String::from( "Thumbnail field has to be a url.", ))); } - if canister_info.clone().frontend.is_some() && !validate_url(&canister_info.frontend.unwrap()) { + if canister_info.clone().frontend.is_some() + && !validate_url(canister_info.clone().frontend.unwrap()) + { return Err(OperationError::BadParameters(String::from( "Frontend field has to be a url.", ))); } - if &canister_info.details[0].0 != String::from("standard") { + if &canister_info.details[0].0 != &String::from("standard") { return Err(OperationError::BadParameters(String::from( "First detail field has to be standard.", ))); diff --git a/registries/tokens/src/common_types.rs b/registries/tokens/src/common_types.rs index 71f85fe..b9aff37 100644 --- a/registries/tokens/src/common_types.rs +++ b/registries/tokens/src/common_types.rs @@ -15,6 +15,9 @@ pub enum DetailValue { Vec(Vec), } +pub const DESCRIPTION_LIMIT: usize = 1200; +pub const NAME_LIMIT: usize = 120; + #[derive(CandidType, Deserialize, Clone, Debug, PartialEq)] pub struct Token { pub name: String, @@ -35,7 +38,7 @@ pub struct GetAllPaginatedResponse { pub enum OperationError { NotAuthorized, NonExistentItem, - BadParameters, + BadParameters(String), Unknown(String), } diff --git a/registries/tokens/src/tokens.rs b/registries/tokens/src/tokens.rs index 1551d93..816fd6f 100644 --- a/registries/tokens/src/tokens.rs +++ b/registries/tokens/src/tokens.rs @@ -49,17 +49,22 @@ impl TokenRegistry { self.0.values().collect() } - pub fn get_all_paginated(&self, offset: usize, _limit: usize) -> Result, OperationError> { - + pub fn get_all_paginated( + &self, + offset: usize, + _limit: usize, + ) -> Result, OperationError> { let tokens: Vec<&Token> = self.0.values().collect(); if offset > tokens.len() { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(String::from( + "Offset out of bound.", + ))); } let mut limit = _limit; - if offset + _limit > tokens.len() { + if offset + _limit > tokens.len() { limit = tokens.len() - offset; } @@ -88,27 +93,63 @@ pub async fn add(token: Token) -> Result<(), OperationError> { return Err(OperationError::NotAuthorized); } - // Check URLs - if !validate_url(&token.thumbnail) || !token.clone().frontend.map(validate_url).unwrap_or(true) - { - return Err(OperationError::BadParameters); + if &token.name.len() > &NAME_LIMIT { + return Err(OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ))); + } + + if &token.description.len() > &DESCRIPTION_LIMIT { + return Err(OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ))); + } + + if !validate_url(&token.thumbnail) { + return Err(OperationError::BadParameters(String::from( + "Thumbnail field has to be a url.", + ))); + } + + if token.clone().frontend.is_some() && !validate_url(token.clone().frontend.unwrap()) { + return Err(OperationError::BadParameters(String::from( + "Frontend field has to be a url.", + ))); + } + + if &token.details.len() < &4 { + return Err(OperationError::BadParameters(String::from( + "Details field has to specifiy: symbol, standard, total_supply and verified fields.", + ))); + } + + if &token.details[0].0 != &String::from("symbol") { + return Err(OperationError::BadParameters(String::from( + "First detail field has to be symbol.", + ))); + } + + if &token.details[1].0 != &String::from("standard") { + return Err(OperationError::BadParameters(String::from( + "Second detail field has to be standard.", + ))); } - // Check Character Limits - let name = token.name.clone(); - if name.len() > 120 && &token.description.len() > &1200 { - return Err(OperationError::BadParameters); + if &token.details[2].0 != &String::from("total_supply") { + return Err(OperationError::BadParameters(String::from( + "Third detail field has to be total_supply.", + ))); } - // Check details - if token.details.len() != 4 - || token.details[0].0 != String::from("symbol") - || token.details[1].0 != String::from("standard") - || token.details[2].0 != String::from("total_supply") - || token.details[3].0 != String::from("verified") - || (token.details[3].1 != DetailValue::True && token.details[3].1 != DetailValue::False) + if &token.details[0].0 != &String::from("verified") + && &token.details[3].1 != &DetailValue::True + && &token.details[3].1 != &DetailValue::False { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(String::from( + "Fourth detail field has to be verified (boolean).", + ))); } // Add the collection to the canister registry @@ -158,13 +199,13 @@ pub fn get_all() -> Vec<&'static Token> { } #[query] -pub fn get_all_paginated(offset: Option, limit: Option) -> Result { +pub fn get_all_paginated( + offset: Option, + limit: Option, +) -> Result { let db = ic::get_mut::(); let tokens = db.get_all_paginated(offset.unwrap_or(0), limit.unwrap_or(DEFAULT_LIMIT))?; let amount = db.get_amount(); - return Ok(GetAllPaginatedResponse{ - tokens, - amount, - }); + return Ok(GetAllPaginatedResponse { tokens, amount }); } From a2c2aff175ee621c4e350f94441f5fa37da789a0 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:18:22 -0300 Subject: [PATCH 07/15] Updated address_book --- registries/address_book/src/address_book.rs | 34 +++++++++++++-------- registries/address_book/src/common_types.rs | 2 +- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/registries/address_book/src/address_book.rs b/registries/address_book/src/address_book.rs index 0cef6bf..8da3922 100644 --- a/registries/address_book/src/address_book.rs +++ b/registries/address_book/src/address_book.rs @@ -64,14 +64,14 @@ impl AddressBook { match address { AddressType::Icns(s) => match self.validate_icns(s).await { true => return Ok(()), - false => return Err(OperationError::BadParameters), + false => return Err(OperationError::BadParameters(String::from("Invalid ICNS."))), }, AddressType::AccountId(s) => match self.validate_account_id(s) { true => return Ok(()), - false => return Err(OperationError::BadParameters), + false => return Err(OperationError::BadParameters(String::from("Invalid Account."))), }, AddressType::PrincipalId(_s) => Ok(()), - _ => Err(OperationError::BadParameters), + _ => Err(OperationError::BadParameters(String::from("Invalid Principal."))), } } @@ -113,10 +113,6 @@ impl AddressBook { ) -> Result, OperationError> { let mut limit = _limit; - if offset >= limit { - return Err(OperationError::BadParameters); - } - let start: Key = (account.clone(), String::new()); let end: Key = (account.clone(), unsafe { String::from(std::char::from_u32_unchecked(u32::MAX)) @@ -124,6 +120,10 @@ impl AddressBook { let addresses: Vec<(&(ic_kit::Principal, std::string::String), &Address)> = self.0.range((Included(start), Included(end))).collect(); + if offset >= addresses.len() { + return Err(OperationError::BadParameters(String::from("Offset out of bound."))); + } + if offset + limit > addresses.len() { limit = addresses.len() - offset; } @@ -140,18 +140,28 @@ fn name() -> String { #[update] pub async fn add(address: Address) -> Result<(), OperationError> { if &address.name.len() > &NAME_LIMIT { - return Err(OperationError::BadParameters); - } else if address.description.is_some() { + return Err(OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ))); + } + + if address.description.is_some() { let description = address.clone().description.unwrap(); if &description.len() > &DESCRIPTION_LIMIT { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ))); } - } else if address.emoji.is_some() { + } + + if address.emoji.is_some() { let emojis: Vec = address.clone().emoji.unwrap().chars().take(1).collect(); if !is_emoji(emojis[0]) { - return Err(OperationError::BadParameters); + return Err(OperationError::BadParameters(String::from("Invalid emoji field."))); } } diff --git a/registries/address_book/src/common_types.rs b/registries/address_book/src/common_types.rs index d805101..4e10e4d 100644 --- a/registries/address_book/src/common_types.rs +++ b/registries/address_book/src/common_types.rs @@ -38,7 +38,7 @@ pub const DEFAULT_LIMIT: usize = 20; #[derive(CandidType, Debug, PartialEq)] pub enum OperationError { NotAuthorized, - BadParameters, + BadParameters(String), NonExistentItem, Unknown(String), } From d2ecffcdabffda2dbd0da4a0d86bf0cb7c619436 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:18:39 -0300 Subject: [PATCH 08/15] Ran cargo fmt --- registries/address_book/src/address_book.rs | 26 ++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/registries/address_book/src/address_book.rs b/registries/address_book/src/address_book.rs index 8da3922..dcaee0f 100644 --- a/registries/address_book/src/address_book.rs +++ b/registries/address_book/src/address_book.rs @@ -68,10 +68,16 @@ impl AddressBook { }, AddressType::AccountId(s) => match self.validate_account_id(s) { true => return Ok(()), - false => return Err(OperationError::BadParameters(String::from("Invalid Account."))), + false => { + return Err(OperationError::BadParameters(String::from( + "Invalid Account.", + ))) + } }, AddressType::PrincipalId(_s) => Ok(()), - _ => Err(OperationError::BadParameters(String::from("Invalid Principal."))), + _ => Err(OperationError::BadParameters(String::from( + "Invalid Principal.", + ))), } } @@ -121,7 +127,9 @@ impl AddressBook { self.0.range((Included(start), Included(end))).collect(); if offset >= addresses.len() { - return Err(OperationError::BadParameters(String::from("Offset out of bound."))); + return Err(OperationError::BadParameters(String::from( + "Offset out of bound.", + ))); } if offset + limit > addresses.len() { @@ -144,8 +152,8 @@ pub async fn add(address: Address) -> Result<(), OperationError> { "Name field has to be less than {} characters long.", NAME_LIMIT ))); - } - + } + if address.description.is_some() { let description = address.clone().description.unwrap(); @@ -155,13 +163,15 @@ pub async fn add(address: Address) -> Result<(), OperationError> { DESCRIPTION_LIMIT ))); } - } - + } + if address.emoji.is_some() { let emojis: Vec = address.clone().emoji.unwrap().chars().take(1).collect(); if !is_emoji(emojis[0]) { - return Err(OperationError::BadParameters(String::from("Invalid emoji field."))); + return Err(OperationError::BadParameters(String::from( + "Invalid emoji field.", + ))); } } From 69265517ae922009fbc5fab61daa240b6da7d125 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:20:13 -0300 Subject: [PATCH 09/15] Updated .did files --- candid/address_book.did | 2 +- candid/nft.did | 2 +- candid/registry.did | 2 +- candid/tokens.did | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/candid/address_book.did b/candid/address_book.did index 1eea533..2d6ca61 100644 --- a/candid/address_book.did +++ b/candid/address_book.did @@ -14,7 +14,7 @@ type value_type = variant { type operation_error = variant { NotAuthorized; NonExistentItem; - BadParameters; + BadParameters: text; Unknown : text; }; diff --git a/candid/nft.did b/candid/nft.did index d550877..2f31279 100644 --- a/candid/nft.did +++ b/candid/nft.did @@ -27,7 +27,7 @@ type paginated_nft_canisters = record { type operation_error = variant { NotAuthorized; NonExistentItem; - BadParameters; + BadParameters: text; Unknown : text; }; diff --git a/candid/registry.did b/candid/registry.did index 988d620..ab9fea4 100644 --- a/candid/registry.did +++ b/candid/registry.did @@ -26,7 +26,7 @@ type paginated_canister_metadata = record { type operation_error = variant { NotAuthorized; - BadParameters; + BadParameters: text; NonExistentItem; Unknown: text; }; diff --git a/candid/tokens.did b/candid/tokens.did index 3478cd7..b40d221 100644 --- a/candid/tokens.did +++ b/candid/tokens.did @@ -27,7 +27,7 @@ type paginated_tokens = record { type operation_error = variant { NotAuthorized; NonExistentItem; - BadParameters; + BadParameters: text; Unknown : text; }; From f63f88b15184f3af9509cb26778692faf38886de Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:23:49 -0300 Subject: [PATCH 10/15] Fixed canister_registry tests --- registries/canister_registry/src/tests.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/registries/canister_registry/src/tests.rs b/registries/canister_registry/src/tests.rs index 823775d..fe78806 100644 --- a/registries/canister_registry/src/tests.rs +++ b/registries/canister_registry/src/tests.rs @@ -128,7 +128,7 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from("Thumbnail field has to be a url."))); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); @@ -156,7 +156,9 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( + "Frontend field has to be a url.", + ))); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); From 953eac4f09793942efe51c8cc9ced290ce89ebda Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:46:23 -0300 Subject: [PATCH 11/15] Fixed nft tests --- registries/nft/src/nft.rs | 12 ++++++++---- registries/nft/src/tests.rs | 26 ++++++++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index a52d025..075244b 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -85,7 +85,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { return Err(OperationError::NotAuthorized); } - if &canister_info.name.len() > &NAME_LIMIT { + if canister_info.clone().name.len() > NAME_LIMIT { return Err(OperationError::BadParameters( format!( "Name field has to be less than {} characters long.", @@ -95,7 +95,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { )); } - if &canister_info.description.len() > &DESCRIPTION_LIMIT { + if canister_info.clone().description.len() > DESCRIPTION_LIMIT { return Err(OperationError::BadParameters( format!( "Description field has to be less than {} characters long.", @@ -105,7 +105,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { )); } - if !validate_url(&canister_info.thumbnail) { + if !validate_url(canister_info.clone().thumbnail) { return Err(OperationError::BadParameters(String::from( "Thumbnail field has to be a url.", ))); @@ -119,7 +119,11 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { ))); } - if &canister_info.details[0].0 != &String::from("standard") { + if canister_info.clone().details.len() < 1 { + return Err(OperationError::BadParameters(String::from("Details has to have standard field."))); + } + + if canister_info.clone().details[0].0 != String::from("standard") { return Err(OperationError::BadParameters(String::from( "First detail field has to be standard.", ))); diff --git a/registries/nft/src/tests.rs b/registries/nft/src/tests.rs index 408874b..aab8f38 100644 --- a/registries/nft/src/tests.rs +++ b/registries/nft/src/tests.rs @@ -113,7 +113,11 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ) + .to_string())); } #[tokio::test] @@ -140,7 +144,11 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ) + .to_string())); } #[tokio::test] @@ -165,7 +173,9 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( + "Thumbnail field has to be a url." + ))); } #[tokio::test] @@ -190,7 +200,9 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( + "Frontend field has to be a url." + ))); } #[tokio::test] @@ -215,7 +227,9 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( + "First detail field has to be standard.", + ))); } #[tokio::test] @@ -246,7 +260,7 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from("Details has to have standard field."))); } #[tokio::test] From e47c23d96f610576dfce9329823a1cfe06a10658 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Thu, 28 Apr 2022 23:49:48 -0300 Subject: [PATCH 12/15] Fixed address_book tests --- registries/address_book/src/tests.rs | 46 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/registries/address_book/src/tests.rs b/registries/address_book/src/tests.rs index 9b9ac57..8a9d5db 100644 --- a/registries/address_book/src/tests.rs +++ b/registries/address_book/src/tests.rs @@ -69,7 +69,10 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ))); } #[tokio::test] @@ -87,26 +90,31 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ))); } - // #[tokio::test] - // async fn test_add_address_fails_because_of_bad_emoji_param() { - // MockContext::new() - // .with_caller(mock_principals::alice()) - // .inject(); - - // let address_info = Address { - // name: String::from("Bob"), - // description: Some(String::from("description")), - // emoji: Some(String::from("a")), - // value: AddressType::PrincipalId(mock_principals::bob()), - // }; - - // let addition_result = add(address_info.clone()).await; - // assert!(addition_result.is_err()); - // assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters); - // } + #[tokio::test] + async fn test_add_address_fails_because_of_bad_emoji_param() { + MockContext::new() + .with_caller(mock_principals::alice()) + .inject(); + + let address_info = Address { + name: String::from("Bob"), + description: Some(String::from("description")), + emoji: Some(String::from("a")), + value: AddressType::PrincipalId(mock_principals::bob()), + }; + + let addition_result = add(address_info.clone()).await; + assert!(addition_result.is_err()); + assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( + "Invalid emoji field.", + ))); + } #[tokio::test] async fn test_remove_address_successfully() { From 2b3385b8033b3796a41d72bdea7b00e4589ca5e3 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Fri, 29 Apr 2022 00:02:14 -0300 Subject: [PATCH 13/15] Updated ic_kit version --- registries/canister_registry/Cargo.toml | 2 +- registries/nft/Cargo.toml | 2 +- registries/tokens/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/registries/canister_registry/Cargo.toml b/registries/canister_registry/Cargo.toml index b3569c0..d93af30 100644 --- a/registries/canister_registry/Cargo.toml +++ b/registries/canister_registry/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.3" +ic-cdk = "0.5" ic-cdk-macros = "0.3" ic-types = "0.1.3" ic-kit = "0.4.2" diff --git a/registries/nft/Cargo.toml b/registries/nft/Cargo.toml index 898233a..0751c9f 100644 --- a/registries/nft/Cargo.toml +++ b/registries/nft/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.3" +ic-cdk = "0.5" ic-cdk-macros = "0.3" ic-types = "0.1.3" serde = "1.0.116" diff --git a/registries/tokens/Cargo.toml b/registries/tokens/Cargo.toml index 7109980..30d4a8d 100644 --- a/registries/tokens/Cargo.toml +++ b/registries/tokens/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -ic-cdk = "0.3" +ic-cdk = "0.5" ic-cdk-macros = "0.3" ic-types = "0.1.3" serde = "1.0.116" From 78db312a986188489769874a24b43f688374f489 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Fri, 29 Apr 2022 00:14:17 -0300 Subject: [PATCH 14/15] removed unnecessary references --- registries/address_book/src/address_book.rs | 4 ++-- registries/canister_registry/src/registry.rs | 6 +++--- registries/nft/src/nft.rs | 10 +++++----- registries/tokens/src/tokens.rs | 20 ++++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/registries/address_book/src/address_book.rs b/registries/address_book/src/address_book.rs index dcaee0f..4fa8dfe 100644 --- a/registries/address_book/src/address_book.rs +++ b/registries/address_book/src/address_book.rs @@ -147,7 +147,7 @@ fn name() -> String { #[update] pub async fn add(address: Address) -> Result<(), OperationError> { - if &address.name.len() > &NAME_LIMIT { + if address.name.len() > NAME_LIMIT { return Err(OperationError::BadParameters(format!( "Name field has to be less than {} characters long.", NAME_LIMIT @@ -157,7 +157,7 @@ pub async fn add(address: Address) -> Result<(), OperationError> { if address.description.is_some() { let description = address.clone().description.unwrap(); - if &description.len() > &DESCRIPTION_LIMIT { + if description.len() > DESCRIPTION_LIMIT { return Err(OperationError::BadParameters(format!( "Description field has to be less than {} characters long.", DESCRIPTION_LIMIT diff --git a/registries/canister_registry/src/registry.rs b/registries/canister_registry/src/registry.rs index 84c22ae..38d6cfe 100644 --- a/registries/canister_registry/src/registry.rs +++ b/registries/canister_registry/src/registry.rs @@ -96,14 +96,14 @@ pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { return Err(OperationError::NotAuthorized); } - if &metadata.name.len() > &NAME_LIMIT { + if metadata.name.len() > NAME_LIMIT { return Err(OperationError::BadParameters(format!( "Name field has to be less than {} characters long.", NAME_LIMIT ))); } - if &metadata.description.len() > &DESCRIPTION_LIMIT { + if metadata.description.len() > DESCRIPTION_LIMIT { return Err(OperationError::BadParameters(format!( "Description field has to be less than {} characters long.", DESCRIPTION_LIMIT @@ -116,7 +116,7 @@ pub fn add(metadata: CanisterMetadata) -> Result<(), OperationError> { ))); } - if metadata.clone().frontend.is_some() && !validate_url(metadata.clone().frontend.unwrap()) { + if metadata.frontend.is_some() && !validate_url(metadata.clone().frontend.unwrap()) { return Err(OperationError::BadParameters(String::from( "Frontend field has to be a url.", ))); diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index 075244b..c7fb6fc 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -85,7 +85,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { return Err(OperationError::NotAuthorized); } - if canister_info.clone().name.len() > NAME_LIMIT { + if canister_info.name.len() > NAME_LIMIT { return Err(OperationError::BadParameters( format!( "Name field has to be less than {} characters long.", @@ -95,7 +95,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { )); } - if canister_info.clone().description.len() > DESCRIPTION_LIMIT { + if canister_info.description.len() > DESCRIPTION_LIMIT { return Err(OperationError::BadParameters( format!( "Description field has to be less than {} characters long.", @@ -111,7 +111,7 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { ))); } - if canister_info.clone().frontend.is_some() + if canister_info.frontend.is_some() && !validate_url(canister_info.clone().frontend.unwrap()) { return Err(OperationError::BadParameters(String::from( @@ -119,11 +119,11 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { ))); } - if canister_info.clone().details.len() < 1 { + if canister_info.details.len() < 1 { return Err(OperationError::BadParameters(String::from("Details has to have standard field."))); } - if canister_info.clone().details[0].0 != String::from("standard") { + if canister_info.details[0].0 != String::from("standard") { return Err(OperationError::BadParameters(String::from( "First detail field has to be standard.", ))); diff --git a/registries/tokens/src/tokens.rs b/registries/tokens/src/tokens.rs index 816fd6f..175ff3d 100644 --- a/registries/tokens/src/tokens.rs +++ b/registries/tokens/src/tokens.rs @@ -93,14 +93,14 @@ pub async fn add(token: Token) -> Result<(), OperationError> { return Err(OperationError::NotAuthorized); } - if &token.name.len() > &NAME_LIMIT { + if token.name.len() > NAME_LIMIT { return Err(OperationError::BadParameters(format!( "Name field has to be less than {} characters long.", NAME_LIMIT ))); } - if &token.description.len() > &DESCRIPTION_LIMIT { + if token.description.len() > DESCRIPTION_LIMIT { return Err(OperationError::BadParameters(format!( "Description field has to be less than {} characters long.", DESCRIPTION_LIMIT @@ -113,39 +113,39 @@ pub async fn add(token: Token) -> Result<(), OperationError> { ))); } - if token.clone().frontend.is_some() && !validate_url(token.clone().frontend.unwrap()) { + if token.frontend.is_some() && !validate_url(token.clone().frontend.unwrap()) { return Err(OperationError::BadParameters(String::from( "Frontend field has to be a url.", ))); } - if &token.details.len() < &4 { + if token.details.len() < 4 { return Err(OperationError::BadParameters(String::from( "Details field has to specifiy: symbol, standard, total_supply and verified fields.", ))); } - if &token.details[0].0 != &String::from("symbol") { + if token.details[0].0 != String::from("symbol") { return Err(OperationError::BadParameters(String::from( "First detail field has to be symbol.", ))); } - if &token.details[1].0 != &String::from("standard") { + if token.details[1].0 != String::from("standard") { return Err(OperationError::BadParameters(String::from( "Second detail field has to be standard.", ))); } - if &token.details[2].0 != &String::from("total_supply") { + if token.details[2].0 != String::from("total_supply") { return Err(OperationError::BadParameters(String::from( "Third detail field has to be total_supply.", ))); } - if &token.details[0].0 != &String::from("verified") - && &token.details[3].1 != &DetailValue::True - && &token.details[3].1 != &DetailValue::False + if token.details[0].0 != String::from("verified") + && token.details[3].1 != DetailValue::True + && token.details[3].1 != DetailValue::False { return Err(OperationError::BadParameters(String::from( "Fourth detail field has to be verified (boolean).", From 73e568b88418685bc0c47ca8e7db4f886d599e08 Mon Sep 17 00:00:00 2001 From: migue toscano Date: Fri, 29 Apr 2022 00:14:54 -0300 Subject: [PATCH 15/15] carfgo fmt --- registries/address_book/src/tests.rs | 29 +++++++----- registries/canister_registry/src/tests.rs | 12 +++-- registries/nft/src/nft.rs | 8 ++-- registries/nft/src/tests.rs | 56 +++++++++++++++-------- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/registries/address_book/src/tests.rs b/registries/address_book/src/tests.rs index 8a9d5db..d0fd3a2 100644 --- a/registries/address_book/src/tests.rs +++ b/registries/address_book/src/tests.rs @@ -69,10 +69,13 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( - "Description field has to be less than {} characters long.", - DESCRIPTION_LIMIT - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + )) + ); } #[tokio::test] @@ -90,10 +93,13 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( - "Name field has to be less than {} characters long.", - NAME_LIMIT - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + )) + ); } #[tokio::test] @@ -111,9 +117,10 @@ mod tests { let addition_result = add(address_info.clone()).await; assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( - "Invalid emoji field.", - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Invalid emoji field.",)) + ); } #[tokio::test] diff --git a/registries/canister_registry/src/tests.rs b/registries/canister_registry/src/tests.rs index fe78806..2d97068 100644 --- a/registries/canister_registry/src/tests.rs +++ b/registries/canister_registry/src/tests.rs @@ -128,7 +128,10 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from("Thumbnail field has to be a url."))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Thumbnail field has to be a url.")) + ); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); @@ -156,9 +159,10 @@ mod tests { let addition_result = add(canister_metadata.clone()); assert!(addition_result.is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( - "Frontend field has to be a url.", - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Frontend field has to be a url.",)) + ); let added_canister = get(mock_principals::xtc()); assert!(added_canister.is_none()); diff --git a/registries/nft/src/nft.rs b/registries/nft/src/nft.rs index c7fb6fc..f6c4c22 100644 --- a/registries/nft/src/nft.rs +++ b/registries/nft/src/nft.rs @@ -111,16 +111,16 @@ pub async fn add(canister_info: NftCanister) -> Result<(), OperationError> { ))); } - if canister_info.frontend.is_some() - && !validate_url(canister_info.clone().frontend.unwrap()) - { + if canister_info.frontend.is_some() && !validate_url(canister_info.clone().frontend.unwrap()) { return Err(OperationError::BadParameters(String::from( "Frontend field has to be a url.", ))); } if canister_info.details.len() < 1 { - return Err(OperationError::BadParameters(String::from("Details has to have standard field."))); + return Err(OperationError::BadParameters(String::from( + "Details has to have standard field.", + ))); } if canister_info.details[0].0 != String::from("standard") { diff --git a/registries/nft/src/tests.rs b/registries/nft/src/tests.rs index aab8f38..6f07b90 100644 --- a/registries/nft/src/tests.rs +++ b/registries/nft/src/tests.rs @@ -113,11 +113,16 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( - "Name field has to be less than {} characters long.", - NAME_LIMIT - ) - .to_string())); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters( + format!( + "Name field has to be less than {} characters long.", + NAME_LIMIT + ) + .to_string() + ) + ); } #[tokio::test] @@ -144,11 +149,16 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(format!( - "Description field has to be less than {} characters long.", - DESCRIPTION_LIMIT - ) - .to_string())); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters( + format!( + "Description field has to be less than {} characters long.", + DESCRIPTION_LIMIT + ) + .to_string() + ) + ); } #[tokio::test] @@ -173,9 +183,10 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( - "Thumbnail field has to be a url." - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Thumbnail field has to be a url.")) + ); } #[tokio::test] @@ -200,9 +211,10 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( - "Frontend field has to be a url." - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Frontend field has to be a url.")) + ); } #[tokio::test] @@ -227,9 +239,10 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from( - "First detail field has to be standard.", - ))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("First detail field has to be standard.",)) + ); } #[tokio::test] @@ -260,7 +273,10 @@ mod tests { let addition_result = add(canister_info).await; assert!(addition_result.clone().is_err()); - assert_eq!(addition_result.unwrap_err(), OperationError::BadParameters(String::from("Details has to have standard field."))); + assert_eq!( + addition_result.unwrap_err(), + OperationError::BadParameters(String::from("Details has to have standard field.")) + ); } #[tokio::test]