1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#![feature(vec_remove_item)]

use hdk::prelude::*;
use holochain_anchors;
use serde_derive::{Deserialize, Serialize};

pub mod handlers;
pub mod progenitor;
pub mod validation;

pub const ROLE_ASSIGNMENT_TYPE: &'static str = "role_assignment";
pub const AGENT_TO_ASSIGNMENT_LINK_TYPE: &'static str = "agent->role_assignment";
pub const ROLE_TO_ASSIGNMENT_LINK_TYPE: &'static str = "role->role_assignment";
pub const ADMIN_ROLE_NAME: &'static str = "Admin";
pub const ANCHOR_LINK_TYPE: &'static str = concat!("holochain_anchors", "::", "anchor_link");

#[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)]
pub struct RoleAssignment {
    pub role_name: String,
    pub agent_address: Address,
    pub previous_assignment_address: Option<Address>,
    pub assigned: bool,
}

impl RoleAssignment {
    pub fn initial(role_name: String, agent_address: Address) -> RoleAssignment {
        RoleAssignment {
            role_name,
            agent_address,
            previous_assignment_address: None,
            assigned: true,
        }
    }

    pub fn entry(&self) -> Entry {
        Entry::App(ROLE_ASSIGNMENT_TYPE.into(), self.into())
    }

    pub fn initial_address(&self) -> ZomeApiResult<Address> {
        let initial_role_entry =
            RoleAssignment::initial(self.role_name.clone(), self.agent_address.clone());

        hdk::entry_address(&initial_role_entry.entry())
    }
}

/**
 * Role assignment entry definition
 * This function must be called from the zome entry point for this mixin to be setup properly
 */
pub fn role_assignment_entry_def() -> ValidatingEntryType {
    entry!(
        name: ROLE_ASSIGNMENT_TYPE,
        description: "role assignment entry that contains a role name and the members of that role",
        sharing: Sharing::Public,
        validation_package: || {
            hdk::ValidationPackageDefinition::Entry
        },
        validation: | _validation_data: hdk::EntryValidationData<RoleAssignment>| {
            match _validation_data {
                hdk::EntryValidationData::Create { validation_data, entry } => {
                    if let Some(_) = entry.previous_assignment_address {
                        // TODO: Uncomment this when update_entry works return Err(String::from("Cannot create a role with a previous entry address"));
                    }

                    validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                },
                hdk::EntryValidationData::Modify { validation_data, .. } => {
                    validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                },
                hdk::EntryValidationData::Delete { validation_data, .. } => {
                    validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                },
            }
        },
        links: [
            from!(
                "%agent_id",
                link_type: AGENT_TO_ASSIGNMENT_LINK_TYPE,

                validation_package: || {
                    hdk::ValidationPackageDefinition::Entry
                },
                validation: |_validation_data: hdk::LinkValidationData| {
                    match _validation_data {
                        hdk::LinkValidationData::LinkAdd { validation_data, .. } => {
                            validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                        },
                        hdk::LinkValidationData::LinkRemove { validation_data, .. } => {
                            validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                        },
                    }
                }
            ),
            from!(
                holochain_anchors::ANCHOR_TYPE,
                link_type: ROLE_TO_ASSIGNMENT_LINK_TYPE,

                validation_package: || {
                    hdk::ValidationPackageDefinition::Entry
                },

                validation: |_validation_data: hdk::LinkValidationData| {
                    match _validation_data {
                        hdk::LinkValidationData::LinkAdd { validation_data, .. } => {
                            validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                        },
                        hdk::LinkValidationData::LinkRemove { validation_data, .. } => {
                            validation::validate_required_role(&validation_data, &String::from(ADMIN_ROLE_NAME))
                        },
                    }
                }
            )
        ]
    )
}