Skip to content

Commit

Permalink
feat: search contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
veeso committed Dec 10, 2024
1 parent 031c321 commit 6874aa5
Show file tree
Hide file tree
Showing 18 changed files with 639 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions docs/canisters/deferred-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- [HTTP Endpoint](#http-endpoint)
- [Get contracts](#get-contracts)
- [Get contract by id](#get-contract-by-id)
- [Contract Properties](#contract-properties)

## Introduction

Expand Down Expand Up @@ -38,6 +39,13 @@ Response:
]
```

It is also possible to filter contracts using query params:

- seller: seller ETH address
- buyer: buyer ETH address
- agency: agency principal
- contract_property: name of the contract property followed by the value (e.g. `contract:garden` => `garden=true`).

### Get contract by id

Get a contract by id
Expand Down Expand Up @@ -83,3 +91,33 @@ Response:
```

> Restricted properties are redacted based on your permissions
## Contract Properties

These are the Properties that may be inserted into the Contract.

| Property | Type | Description |
|-----------------------|--------------|------------------------------------------------|
| contract:name | TextContent | A title for the property |
| contract:description | TextContent | A description for the property |
| contract:image | TextContent | URL or base64 encoded image |
| contract:address | TextContent | Address where the property is located |
| contract:country | TextContent | Country where the property is located |
| contract:continent | TextContent | Continent where the property is located |
| contract:region | TextContent | Region where the property is located |
| contract:zipCode | TextContent | Zip code where the property is located |
| contract:latitude | TextContent | Latitude where the property is located |
| contract:longitude | TextContent | Longitude where the property is located |
| contract:zone | TextContent | Zone of the city where the property is located |
| contract:city | TextContent | City where the property is located |
| contract:squareMeters | Nat64Content | Property square meters |
| contract:rooms | Nat64Content | Amount of rooms |
| contract:bathrooms | Nat64Content | Amount of Bathrooms |
| contract:floors | Nat64Content | Floors |
| contract:balconies | Nat64Content | Amount of balconies |
| contract:garden | BoolContent | Has garden |
| contract:pool | BoolContent | Has pool |
| contract:garage | BoolContent | Has garage |
| contract:parking | BoolContent | Has a private parking |
| contract:energyClass | TextContent | Optional energy class |
| contract:youtubeUrl | TextContent | URL to a YouTube video showcasing the property |
58 changes: 56 additions & 2 deletions integration-tests/src/abi/Deferred.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/declarations/deferred_data/deferred_data.did
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ type RestrictedProperty = record {
value : GenericValue;
access_list : vec RestrictionLevel;
};
type RestrictionLevel = variant { Buyer; Seller; Agent };
type RestrictionLevel = variant { Buyer; Public; Seller; Agent };
type Result = variant { Ok; Err : DeferredDataError };
type Result_1 = variant { Ok : ContractDocumentData; Err : DeferredDataError };
type Result_2 = variant { Ok : nat64; Err : DeferredDataError };
Expand Down
1 change: 1 addition & 0 deletions src/declarations/deferred_data/deferred_data.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export interface RestrictedProperty {
'access_list' : Array<RestrictionLevel>,
}
export type RestrictionLevel = { 'Buyer' : null } |
{ 'Public' : null } |
{ 'Seller' : null } |
{ 'Agent' : null };
export type Result = { 'Ok' : null } |
Expand Down
1 change: 1 addition & 0 deletions src/declarations/deferred_data/deferred_data.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const idlFactory = ({ IDL }) => {
const Result = IDL.Variant({ 'Ok' : IDL.Null, 'Err' : DeferredDataError });
const RestrictionLevel = IDL.Variant({
'Buyer' : IDL.Null,
'Public' : IDL.Null,
'Seller' : IDL.Null,
'Agent' : IDL.Null,
});
Expand Down
2 changes: 1 addition & 1 deletion src/declarations/deferred_minter/deferred_minter.did
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ type RestrictedProperty = record {
value : GenericValue;
access_list : vec RestrictionLevel;
};
type RestrictionLevel = variant { Buyer; Seller; Agent };
type RestrictionLevel = variant { Buyer; Public; Seller; Agent };
type Result = variant { Ok; Err : DeferredMinterError };
type Result_1 = variant { Ok : nat; Err : DeferredMinterError };
type Result_2 = variant { Ok : text; Err : DeferredMinterError };
Expand Down
1 change: 1 addition & 0 deletions src/declarations/deferred_minter/deferred_minter.did.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export interface RestrictedProperty {
'access_list' : Array<RestrictionLevel>,
}
export type RestrictionLevel = { 'Buyer' : null } |
{ 'Public' : null } |
{ 'Seller' : null } |
{ 'Agent' : null };
export type Result = { 'Ok' : null } |
Expand Down
1 change: 1 addition & 0 deletions src/declarations/deferred_minter/deferred_minter.did.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export const idlFactory = ({ IDL }) => {
});
const RestrictionLevel = IDL.Variant({
'Buyer' : IDL.Null,
'Public' : IDL.Null,
'Seller' : IDL.Null,
'Agent' : IDL.Null,
});
Expand Down
1 change: 1 addition & 0 deletions src/deferred_data/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ url = { workspace = true }

[dev-dependencies]
pretty_assertions = "1"
serde_json = { workspace = true }
tokio = { version = "1", features = ["full"] }
2 changes: 1 addition & 1 deletion src/deferred_data/deferred_data.did
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ type RestrictedProperty = record {
value : GenericValue;
access_list : vec RestrictionLevel;
};
type RestrictionLevel = variant { Buyer; Seller; Agent };
type RestrictionLevel = variant { Buyer; Public; Seller; Agent };
type Result = variant { Ok; Err : DeferredDataError };
type Result_1 = variant { Ok : ContractDocumentData; Err : DeferredDataError };
type Result_2 = variant { Ok : nat64; Err : DeferredDataError };
Expand Down
8 changes: 4 additions & 4 deletions src/deferred_data/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod inspect;
mod memory;
mod storage;
#[cfg(test)]
mod test_utils;
pub mod test_utils;

use candid::{Nat, Principal};
use did::deferred::{
Expand All @@ -15,10 +15,10 @@ use ethers_core::abi::ethereum_types::H520;
use ic_log::did::Pagination;
use ic_log::writer::Logs;
use ic_log::{init_log, take_memory_records};
use storage::ContractStorage;

use self::configuration::Configuration;
pub use self::inspect::Inspect;
pub use self::storage::ContractStorage;
use crate::utils::{caller, cycles};

/// A message used to verify the ownership of a contract (seller or buyer)
Expand Down Expand Up @@ -182,7 +182,7 @@ impl DeferredData {
} else if let Some(signature) = signature {
Inspect::inspect_signature(&contract.id, signature.signature, signature.message)?
} else {
return Err(DeferredDataError::Unauthorized);
RestrictionLevel::Public
};

// check if we have access
Expand Down Expand Up @@ -212,7 +212,7 @@ impl DeferredData {
} else if let Some(signature) = signature {
Inspect::inspect_signature(&contract.id, signature.signature, signature.message).ok()
} else {
None
Some(RestrictionLevel::Public)
};

// if no access level, redact all
Expand Down
50 changes: 50 additions & 0 deletions src/deferred_data/src/app/storage/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ impl ContractStorage {
})
}

/// get contracts by filter
pub fn get_contracts_filter(filter: impl Fn(&Contract) -> bool) -> Vec<ID> {
with_contracts(|contracts| {
contracts
.iter()
.filter(|(_, contract)| !contract.closed && filter(contract))
.map(|(key, _)| key.0.clone())
.collect()
})
}

/// Update contract property
pub fn update_contract_property(
contract_id: &ID,
Expand Down Expand Up @@ -153,6 +164,7 @@ impl ContractStorage {
#[cfg(test)]
mod test {

use candid::Nat;
use did::deferred::{RestrictionLevel, Seller};
use did::H160;
use pretty_assertions::assert_eq;
Expand Down Expand Up @@ -195,6 +207,44 @@ mod test {
assert_eq!(ContractStorage::get_contracts(), vec![contract.id]);
}

#[test]
fn test_should_filter_contracts() {
let seller = vec![Seller {
address: H160::zero(),
quota: 100,
}];

let contract = with_mock_contract(1, 2, |contract| {
contract.sellers = seller.clone();
contract.buyers = vec![];
});
// store
ContractStorage::insert_contract(contract.clone());

// other contract
let contract = with_mock_contract(2, 2, |contract| {
contract.sellers = seller;
contract.buyers = vec![];

contract.properties.push((
"contract:cryptomadonne".to_string(),
GenericValue::TextContent("Yes".to_string()),
));
});

// store
ContractStorage::insert_contract(contract.clone());

// filter
let contracts = ContractStorage::get_contracts_filter(|contract| {
contract
.properties
.iter()
.any(|(k, _)| k == "contract:cryptomadonne")
});
assert_eq!(contracts, vec![Nat::from(2u64)]);
}

#[test]
fn test_should_update_contract_property() {
let contract = with_mock_contract(1, 1, |contract| {
Expand Down
Loading

0 comments on commit 6874aa5

Please sign in to comment.