# Contacts Zome ###### tags: `Kizuna-architecture` <img src="https://i.imgur.com/IxrnWIH.png" width=200 align="inline"/> User Stories - * [get a list of all of my blocked contacts](https://beyonder.atlassian.net/browse/KIZUNA-23) * [get a list of all of my contacts](https://beyonder.atlassian.net/browse/KIZUNA-22) * [add another user to contacts](https://beyonder.atlassian.net/browse/KIZUNA-10) * [remove someone from contacts](https://beyonder.atlassian.net/browse/KIZUNA-19) * [block someone from contacts](https://beyonder.atlassian.net/browse/KIZUNA-20) * [unblock someone from contacts](https://beyonder.atlassian.net/browse/KIZUNA-21) * [I don't want to receive messages from contacts that I blocked](https://beyonder.atlassian.net/browse/KIZUNA-294) * [check whether an agent is in my contacts](https://beyonder.atlassian.net/browse/KIZUNA-24) * [check whether an agent is in my blocked list](https://beyonder.atlassian.net/browse/KIZUNA-409) ### Comments - username -> agentpubkey (in ui work with agentpubkey not username) - return error instead - accommodate multiple agents to be operated on ## Entry Structure ```rust= enum ContactType { Add, Remove, Block, Unblock, AddToCategory } struct CategoryWithId { id: String, name: String, } #[hdk_entry(id = "contact", visibility = "private")] pub struct Contacts { // allows multiple agents to be added etc. agent_ids: Vec<AgentPubkey>, created: Timestamp, contact_type: ContactType, category: Option<CategoryWithId> } #[hdk_entry(id = "category", visibility = "private")] pub struct Category { name: String, } #[hdk_entry(id = "alias", visibility = "private")] pub struct Alias { id: AgentPubKey, first_name: Option<String>, last_name: Option<String> } ``` ## Contact Entry Conditionals - This is to show the general pattern of OpType that can be done to a Contact entry ![](https://i.imgur.com/WrHf8bg.png) ## Zome Fn ### `add_contacts` ```rust pub fn add_contacts(agent_ids: AgentPubKeysWrapper) -> ExternResult<AgentPubKeysWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell AUI-->>ACD: agent pubkeys ACD-->>ACD: call get_latest_contacts_info() opt same agent was operated as contact before alt added ACD-->>AUI: Err("agent already added") else blocked ACD-->>AUI: Err("agent is blocked") end end ACD-->>ACD: commit Contact entry with ContactType Add ACD-->>AUI: return AgentPubKeysWrapper ``` ### `remove_contacts` ```rust pub fn remove_contacts(agent_ids: AgentPubKeysWrapper) -> ExternResult<AgentPubKeysWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell AUI-->>ACD: agent pubkeys ACD-->>ACD: call get_latest_contacts_info() opt same agent was operated as contact before alt removed/unblocked/None ACD-->>AUI: Err("agent is already removed") else blocked ACD-->>AUI: Err("agent is blocked") end end ACD-->>ACD: commit Contact entry with ContactType Remove ACD-->>AUI: return AgentPubKeysWrapper ``` ### `block_contacts` ```rust pub fn block_contacts(agent_ids: AgentPubKeysWrapper) -> ExternResult<AgentPubKeysWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell AUI-->>ACD: agent pubkeys ACD-->>ACD: call get_latest_contacts_info() opt same agent was operated as contact before alt blocked ACD-->>AUI: Err("this agent is already blocked") end end ACD-->>ACD: commit Contact entry with ContactType Block ACD-->>AUI: return AgentPubKeysWrapper ``` ### `unblock_contacts` ```rust pub fn unblock_contacts(agent_ids: AgentPubKeysWrapper) -> ExternResult<AgentPubKeysWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell AUI-->>ACD: agent pubkeys ACD-->>ACD: call get_latest_contacts_info() opt same agent was operated as contact before alt unblocked/none/removed ACD-->>AUI: Err("agent is already unblocked") else added ACD-->>AUI: Err("agent cannot be unblocked if added") end end ACD-->>ACD: commit Contact entry with ContactType Unblock ACD-->>AUI: AgentPubKeysWrapper ``` ### `list_added_or_blocked` - helper function used for the zome fn `list_added` and `list_blocked` ```rust pub struct AgentPubKeysWrapper(pub Vec<AgentPubkey>) pub fn list_added_or_blocked(filter: ContactType) -> ExternResult<AgentPubKeysWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell AUI-->>ACD: call list_added() or list_blocked() ACD-->>ACD: create an empty HashMap<AgentPubKey, Vec<Contact>> ACD-->>ACD: query all Contacts loop for contact in queried contacts alt first Contact for an agent ACD-->>ACD: insert the contact with key being agentpubkey else agent already has another Contact entry ACD-->>ACD: push the contact to Vec<Contact> end end loop for agentpubkey in HashMap ACD-->>ACD: check the latest Contact for the agent with created field alt both filter and latest Contact's Contact Type are ContactType:Add ACD-->>ACD: include the agentpubkey of agent in AgentPubKeysWrapper else both filter and latest Contact's Contact Type are ContactType:Block ACD-->>ACD: include the agentpubkey of agent in AgentPubKeysWrapper else other ContactType ACD-->>ACD: ignore end end ACD-->>AUI: return AgentPubKeysWrapper ``` ### `in_contacts` - needs to check if this function is still needed ```rust pub struct BooleanWrapper(pub bool); pub fn in_contacts(agent_pubkey: AgentPubKey) -> ExternResult<BooleanWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell participant LDHT as Lobby_DHT ACD-->>ACD: call list_added() ACD-->>ACD: check if the given AgentPubKey is part of the contacts ACD-->>ACD: return boolean ``` ### `in_blocked` - needs to check if this function is still needed ```rust pub struct BooleanWrapper(pub bool); pub fn in_blocked(agent_pubkey: AgentPubKey) -> ExternResult<BooleanWrapper> ``` ```mermaid sequenceDiagram participant AUI as Alice_UI participant ACD as Alice_Cell participant LDHT as Lobby_DHT ACD-->>ACD: call list_blocked() ACD-->>ACD: check if the given AgentPubKey is part of the blocked contacts ACD-->>ACD: return boolean ``` ### `update_alias` ```rust pub struct AliasInput { id: AgentPubKey, first_name: Option<String>, last_name: Option<String> } pub fn create_alias(input: AliasInput) -> ExternResult<Alias> ``` ### `list_alias` ```rust pub struct AliasInput { id: AgentPubKey, first_name: String, last_name: String }pub fn list_alias(input: AliasInput) -> ExternResult<Vec<Alias>> ``` ## Redux State ```javascript= type ProfileID = string; export interface Profile { id: ProfileID; username: string; first_name?: string; last_name?: stringl } export interface IndexedContacts { [key: string]: Profile[]; } export interface ContactsState { contacts: Profile[]; blocked: Profile[]; indexedContacts: IndexedContacts; } // redux state const initialState: ContactsState = { contacts: [], indexedContacts: {}, blocked: [], }; ```