Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion candid/address_book.did
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type value_type = variant {
type operation_error = variant {
NotAuthorized;
NonExistentItem;
BadParameters;
BadParameters: text;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to update the standard as well.

Unknown : text;
};

Expand Down
9 changes: 8 additions & 1 deletion candid/nft.did
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ 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;
BadParameters;
BadParameters: text;
Unknown : text;
};

Expand All @@ -40,5 +45,7 @@ service : {

// Canister ethods
"get_all" : () -> (vec nft_canister) query;
"get_all_paginated" : (offset: opt nat64, limit: opt nat64) -> (variant { Ok: paginated_nft_canisters; Err: operation_error });

"add_admin" : (principal) -> (operation_response);
}
8 changes: 7 additions & 1 deletion candid/registry.did
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ 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;
BadParameters: text;
NonExistentItem;
Unknown: text;
};
Expand All @@ -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);
}
8 changes: 7 additions & 1 deletion candid/tokens.did
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ type token = record {
details : vec record { text; detail_value }
};

type paginated_tokens = record {
tokens: vec token;
amount: nat64;
};

type operation_error = variant {
NotAuthorized;
NonExistentItem;
BadParameters;
BadParameters: text;
Unknown : text;
};

Expand All @@ -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);
}
71 changes: 49 additions & 22 deletions registries/address_book/src/address_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,33 +57,46 @@ 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(String::from("Invalid ICNS."))),
},
AddressType::AccountId(s) => match self.validate_account_id(s) {
true => return Ok(()),
false => return Err(Failure::BadParameters),
false => {
return Err(OperationError::BadParameters(String::from(
"Invalid Account.",
)))
}
},
AddressType::PrincipalId(_s) => Ok(()),
_ => Err(Failure::BadParameters),
_ => Err(OperationError::BadParameters(String::from(
"Invalid Principal.",
))),
}
}

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);
Expand All @@ -103,20 +116,22 @@ impl AddressBook {
account: Principal,
offset: usize,
_limit: usize,
) -> Result<Vec<(&Key, &Address)>, Failure> {
) -> Result<Vec<(&Key, &Address)>, OperationError> {
let mut limit = _limit;

if offset >= limit {
return Err(Failure::BadParameters);
}

let start: Key = (account.clone(), String::new());
let end: Key = (account.clone(), unsafe {
String::from(std::char::from_u32_unchecked(u32::MAX))
});
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;
}
Expand All @@ -131,20 +146,32 @@ fn name() -> String {
}

#[update]
pub async fn add(address: Address) -> Result<(), Failure> {
if &address.name.len() > &NAME_LIMIT {
return Err(Failure::BadParameters);
} else if address.description.is_some() {
pub async fn add(address: Address) -> Result<(), OperationError> {
if address.name.len() > NAME_LIMIT {
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(Failure::BadParameters);
if description.len() > DESCRIPTION_LIMIT {
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<char> = address.clone().emoji.unwrap().chars().take(1).collect();

if !is_emoji(emojis[0]) {
return Err(Failure::BadParameters);
return Err(OperationError::BadParameters(String::from(
"Invalid emoji field.",
)));
}
}

Expand All @@ -159,7 +186,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::<AddressBook>();
return address_book.remove(ic::caller(), address_name);
}
Expand All @@ -178,7 +205,7 @@ pub fn get_all() -> Vec<&'static Address> {
pub fn get_all_paginated(
offset: Option<usize>,
limit: Option<usize>,
) -> Result<Vec<&'static Address>, Failure> {
) -> Result<Vec<&'static Address>, OperationError> {
let address_book = ic::get_mut::<AddressBook>();
let addresses = address_book
.get_all_paginated(
Expand Down
4 changes: 2 additions & 2 deletions registries/address_book/src/common_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ 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,
BadParameters(String),
NonExistentItem,
Unknown(String),
}
53 changes: 34 additions & 19 deletions registries/address_book/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ 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(format!(
"Description field has to be less than {} characters long.",
DESCRIPTION_LIMIT
))
);
}

#[tokio::test]
Expand All @@ -87,26 +93,35 @@ 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(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(), Failure::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() {
Expand Down
2 changes: 1 addition & 1 deletion registries/canister_registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
11 changes: 9 additions & 2 deletions registries/canister_registry/src/common_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use ic_kit::{candid::CandidType, Principal};
use serde::{Deserialize, Serialize};

#[derive(CandidType, Debug, PartialEq)]
pub enum Failure {
pub enum OperationError {
NotAuthorized,
BadParameters,
BadParameters(String),
NonExistentItem,
Unknown(String),
}
Expand All @@ -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,
Expand All @@ -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;
10 changes: 5 additions & 5 deletions registries/canister_registry/src/management.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Principal>);

Expand All @@ -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::<Admins>().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::<Admins>().0.retain(|x| *x != admin);
return Ok(());
}
Err(Failure::NotAuthorized)
Err(OperationError::NotAuthorized)
}
Loading