From 05112098185a6898881c9d8027b02fe16c221ad8 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 17 Aug 2020 22:30:07 +0100 Subject: [PATCH 1/8] lib.rs from session 4 --- dna/course/zomes/courses/code/src/lib.rs | 106 ++++------------------- 1 file changed, 15 insertions(+), 91 deletions(-) diff --git a/dna/course/zomes/courses/code/src/lib.rs b/dna/course/zomes/courses/code/src/lib.rs index 4bab334..2ff8124 100644 --- a/dna/course/zomes/courses/code/src/lib.rs +++ b/dna/course/zomes/courses/code/src/lib.rs @@ -1,5 +1,3 @@ -// allowing unstable feature to remove item from the vector on a crate level -#![feature(vec_remove_item)] // allowing for this Rust project to have dead code on a crate level #![allow(dead_code)] // unstable Rust feature @@ -19,14 +17,12 @@ extern crate serde_json; extern crate holochain_json_derive; use hdk::prelude::*; + use hdk_proc_macros::zome; -// Declaring Rust modules that are used in our project mod anchor_trait; -mod content; mod course; mod helper; -mod section; #[zome] mod courses { @@ -59,8 +55,6 @@ mod courses { course::entry::course_entry_def() } - // zome_fn is used to specify that this is a function available to call from our zome - // "hc_public" here means that there are no restrictions as to who can call this function #[zome_fn("hc_public")] fn create_course(title: String, timestamp: u64) -> ZomeApiResult
{ course::handlers::create(title, timestamp) @@ -70,7 +64,13 @@ mod courses { fn get_latest_course_entry( course_anchor_address: Address, ) -> ZomeApiResult> { - course::handlers::get_latest_course_entry(course_anchor_address) + let latest_course_result = course::handlers::get_latest_course(&course_anchor_address)?; + match latest_course_result { + Some((course_entry, _course_entry_address)) => { + return Ok(Some(course_entry)); + } + None => return Ok(None), + } } #[zome_fn("hc_public")] @@ -102,87 +102,11 @@ mod courses { course::handlers::get_my_enrolled_courses() } - #[zome_fn("hc_public")] - fn enrol_in_course(course_anchor_address: Address) -> ZomeApiResult
{ - course::handlers::enrol_in_course(course_anchor_address) - } - - #[zome_fn("hc_public")] - fn get_all_students(course_anchor_address: Address) -> ZomeApiResult> { - course::handlers::get_students(course_anchor_address) - } - - // ====================== Section definitions - #[entry_def] - fn section_anchor_entry_definition() -> ValidatingEntryType { - section::anchor::section_anchor_def() - } - - #[entry_def] - fn section_entry_definition() -> ValidatingEntryType { - section::entry::entry_def() - } - - #[zome_fn("hc_public")] - fn get_latest_section_entry( - section_anchor_address: Address, - ) -> ZomeApiResult> { - section::handlers::get_latest_section_entry(section_anchor_address) - } + // Section + // TODO: implement section entry definitions + // TODO: implement section CRUD methods - #[zome_fn("hc_public")] - fn create_section( - title: String, - course_anchor_address: Address, - timestamp: u64, - ) -> ZomeApiResult
{ - section::handlers::create(title, &course_anchor_address, timestamp) - } - - #[zome_fn("hc_public")] - fn update_section(title: String, section_anchor_address: Address) -> ZomeApiResult
{ - section::handlers::update(title, §ion_anchor_address) - } - - #[zome_fn("hc_public")] - fn delete_section(section_anchor_address: Address) -> ZomeApiResult
{ - section::handlers::delete(section_anchor_address) - } - - // ====================== Content definitions - #[entry_def] - fn content_entry_definition() -> ValidatingEntryType { - content::entry::section_entry_def() - } - - #[zome_fn("hc_public")] - fn create_content( - name: String, - section_anchor_address: Address, - url: String, - timestamp: u64, - description: String, - ) -> ZomeApiResult
{ - content::handlers::create(name, section_anchor_address, url, timestamp, description) - } - - #[zome_fn("hc_public")] - fn get_contents(section_anchor_address: Address) -> ZomeApiResult> { - content::handlers::get_contents(§ion_anchor_address) - } - - #[zome_fn("hc_public")] - fn update_content( - content_address: Address, - name: String, - url: String, - description: String, - ) -> ZomeApiResult
{ - content::handlers::update(content_address, name, url, description) - } - - #[zome_fn("hc_public")] - fn delete_content(content_address: Address) -> ZomeApiResult
{ - content::handlers::delete(content_address) - } -} + // Content + // TODO: implement content entry definition + // TODO: implement content CRUD methods +} \ No newline at end of file From daf6b8b7597bcd33aabdaf92084bc43d7100c7a8 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 17 Aug 2020 22:32:35 +0100 Subject: [PATCH 2/8] setup --- dna/course/zomes/courses/code/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dna/course/zomes/courses/code/src/lib.rs b/dna/course/zomes/courses/code/src/lib.rs index 2ff8124..b786c22 100644 --- a/dna/course/zomes/courses/code/src/lib.rs +++ b/dna/course/zomes/courses/code/src/lib.rs @@ -102,10 +102,14 @@ mod courses { course::handlers::get_my_enrolled_courses() } + // ====================== Section definitions + // Section // TODO: implement section entry definitions // TODO: implement section CRUD methods + // ====================== Content definitions + // Content // TODO: implement content entry definition // TODO: implement content CRUD methods From 92f15d2ba2b248b1732bae79917f834ecf37c81d Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 17 Aug 2020 22:37:46 +0100 Subject: [PATCH 3/8] Implement entry definitions for sections/ content --- dna/course/zomes/courses/code/src/lib.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dna/course/zomes/courses/code/src/lib.rs b/dna/course/zomes/courses/code/src/lib.rs index b786c22..5fc2835 100644 --- a/dna/course/zomes/courses/code/src/lib.rs +++ b/dna/course/zomes/courses/code/src/lib.rs @@ -103,14 +103,25 @@ mod courses { } // ====================== Section definitions - - // Section // TODO: implement section entry definitions + #[entry_def] + fn section_entry_definition() -> ValidatingEntryType { + course::entry::section_entry_def() + } + + #[entry_def] + fn section_anchor_definition() -> ValidatingEntryType { + course::anchor::section_anchor_def() + } + // TODO: implement section CRUD methods // ====================== Content definitions - - // Content // TODO: implement content entry definition + #[entry_def] + fn content_entry_definition() -> ValidatingEntryType { + course::entry::content_entry_def() + } + // TODO: implement content CRUD methods } \ No newline at end of file From 1834da5aae1646dc2c3224c741e96ceb21196a9c Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 18 Aug 2020 14:02:38 +0100 Subject: [PATCH 4/8] Implement course/section CRUD on lib.rs --- dna/course/zomes/courses/code/src/lib.rs | 66 ++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/dna/course/zomes/courses/code/src/lib.rs b/dna/course/zomes/courses/code/src/lib.rs index 5fc2835..0d297d2 100644 --- a/dna/course/zomes/courses/code/src/lib.rs +++ b/dna/course/zomes/courses/code/src/lib.rs @@ -72,7 +72,7 @@ mod courses { None => return Ok(None), } } - + // sections_address - do I need to replicate this in the sections CRUD? Seems weird to update the course this way. #[zome_fn("hc_public")] fn update_course( title: String, @@ -114,14 +114,72 @@ mod courses { course::anchor::section_anchor_def() } - // TODO: implement section CRUD methods + // TODO: implement section CRUD methods --> fished out of modules "impl" right? or handlers? + #[zome_fn("hc_public")] + fn create_section(title: String, course_anchor_address: Address, timestamp: u64, anchor_address: Address, + ) -> ZomeApiResult
{ + section::handlers::create(title, course_anchor_address, timestamp, anchor_address) + } + + #[zome_fn("hc_public")] + fn get_latest_section_entry( + section_anchor_address: Address, + ) -> ZomeApiResult> { + section::handlers::get_latest_section_entry(section_anchor_address)?; + } + // this is copied off the course methods code and changed... is the sections_address part relevant here or in the above code? + #[zome_fn("hc_public")] + fn update_section( + title: String, + course_anchor_address: Address, + timestamp: u64, + anchor_address: Address, + ) -> ZomeApiResult
{ + section::handlers::update(title, course_anchor_address, timestamp, anchor_address) + } + + #[zome_fn("hc_public")] + fn delete_section(section_anchor_address: Address) -> ZomeApiResult
{ + section::handlers::delete(section_anchor_address) + } + // ====================== Content definitions // TODO: implement content entry definition #[entry_def] fn content_entry_definition() -> ValidatingEntryType { - course::entry::content_entry_def() + course::entry::section_entry_def() + } + + // TODO: implement content CRUD methods --> used section anchor addresses as content uses that anchor + #[zome_fn("hc_public")] + fn create_content(name: String, + section_anchor_address: Address, + url: String, + timestamp: u64, + description: String, + ) -> ZomeApiResult
{ + content::handlers::create(name, section_anchor_address, url, timestamp, description) // defined in module + } + + #[zome_fn("hc_public")] + fn get_contents(section_anchor_address: Address) -> ZomeApiResult> { + content::handlers::get_contents(§ion_anchor_address)?; } - // TODO: implement content CRUD methods + #[zome_fn("hc_public")] + fn update_content( + name: String, + section_anchor_address: Address, + url: String, + timestamp: u64, + description: String, + ) -> ZomeApiResult
{ + content::handlers::update(name, url, description, timestamp, section_anchor_address,) + } + + #[zome_fn("hc_public")] + fn delete_content(content_address: Address) -> ZomeApiResult
{ + content::handlers::delete(content_address) + } } \ No newline at end of file From f04232550bb6dbf3657b18543db88aafc77eb5b0 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 20 Aug 2020 20:15:49 +0100 Subject: [PATCH 5/8] Entry validation rules --- .../zomes/courses/code/src/content/entry.rs | 17 +- .../courses/code/src/content/validation.rs | 152 ++++++++++++++++++ .../zomes/courses/code/src/section/entry.rs | 17 +- .../courses/code/src/section/validation.rs | 151 +++++++++++++++++ 4 files changed, 317 insertions(+), 20 deletions(-) create mode 100644 dna/course/zomes/courses/code/src/content/validation.rs create mode 100644 dna/course/zomes/courses/code/src/section/validation.rs diff --git a/dna/course/zomes/courses/code/src/content/entry.rs b/dna/course/zomes/courses/code/src/content/entry.rs index 41a6e02..82a10ec 100644 --- a/dna/course/zomes/courses/code/src/content/entry.rs +++ b/dna/course/zomes/courses/code/src/content/entry.rs @@ -44,18 +44,15 @@ pub fn section_entry_def() -> ValidatingEntryType { hdk::ValidationPackageDefinition::Entry }, validation: | validation_data: hdk::EntryValidationData| { - match validation_data { - EntryValidationData::Create { .. } => { - // TODO: implement validation - Ok(()) + match validation_data { + EntryValidationData::Create { entry, validation_data } => { + validation::create(entry, validation_data) }, - EntryValidationData::Modify { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Modify { new_entry, old_entry, old_entry_header, validation_data } => { + validation::modify(new_entry, old_entry, old_entry_header, validation_data) }, - EntryValidationData::Delete { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Delete { old_entry, old_entry_header, validation_data } => { + validation::delete(old_entry, old_entry_header, validation_data) } } } diff --git a/dna/course/zomes/courses/code/src/content/validation.rs b/dna/course/zomes/courses/code/src/content/validation.rs new file mode 100644 index 0000000..2b8f9a3 --- /dev/null +++ b/dna/course/zomes/courses/code/src/content/validation.rs @@ -0,0 +1,152 @@ +/* + +use super::{ + anchor::CourseAnchor, + catalog_anchor::CourseCatalogAnchor, + entry::{Course, MAX_TITLE_LEN}, +}; +use crate::anchor_trait::AnchorTrait; +use crate::helper; +use hdk::holochain_core_types::chain_header::ChainHeader; +use hdk::{LinkValidationData, ValidationData}; +use holochain_entry_utils::HolochainEntry; + +pub fn create(entry: Course, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "create their courses", + )?; + helper::validate_entity_title(&entry.title, &Course::entry_type(), MAX_TITLE_LEN) +} + +pub fn modify( + new_entry: Course, + old_entry: Course, + _old_entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &old_entry.teacher_address, + validation_data.sources(), + "modify their courses", + )?; + helper::validate_entity_title(&new_entry.title, &Course::entry_type(), MAX_TITLE_LEN)?; + validate_no_teacher_change(old_entry, new_entry) +} + +// this fn is only needed in the current module so it's private +fn validate_no_teacher_change(old_entry: Course, new_entry: Course) -> Result<(), String> { + if new_entry.teacher_address != old_entry.teacher_address { + return Err(String::from("Cannot change the teacher of the course")); + } + Ok(()) +} + +pub fn delete( + entry: Course, + _entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "delete their courses", + ) +} + +// =========================== CourseAnchor validation +pub fn anchor_create(entry: CourseAnchor, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "create their courses", + )?; + helper::validate_entity_title(&entry.title, &CourseAnchor::entry_type(), MAX_TITLE_LEN) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be modified +pub fn anchor_modify() -> Result<(), String> { + Err(String::from( + "Can't modify the CourseAnchor entry: it can only be created or deleted", + )) +} + +pub fn anchor_delete( + entry: CourseAnchor, + _entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "delete their courses", + ) +} + +// =========================== CourseCatalogAnchor validation +// Anyone can create the CourseCatalogAnchor and there isn't anything we need to validate about it +pub fn catalog_create( + _entry: CourseCatalogAnchor, + _validation_data: ValidationData, +) -> Result<(), String> { + Ok(()) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be modified +pub fn catalog_modify() -> Result<(), String> { + Err(String::from("Can't modify the CourseAnchorCatalog entry")) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be deleted +pub fn catalog_delete() -> Result<(), String> { + Err(String::from("Can't delete the CourseAnchorCatalog entry")) +} + +// =========================== CourseAnchor links validation + +pub fn anchor_to_course_link(validation_data: LinkValidationData) -> Result<(), String> { + match validation_data { + hdk::LinkValidationData::LinkAdd { + link, + validation_data, + } => { + // get author of this entry + let author = validation_data.package.chain_header.provenances()[0].source(); + // get link base: entry from which the link goes + let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + // get link target: entry to which the link goes + let target: Course = hdk::utils::get_as_type(link.link.target().clone())?; + if base.teacher_address != target.teacher_address { + // notice that we're using return and ending this statement with ; symbol + // You can do both: skip ; symbol in the last fn statement or explicitly add return to it and then leave ; as is + return Err(String::from( + "Can't link CourseAnchor to Course because their teacher addresses are different", + )); + } else if author != base.teacher_address { + return Err(String::from( + "Can't link CourseAnchor to Course because your address isn't specified as teacher address for this course", + )); + } + Ok(()) + } + hdk::LinkValidationData::LinkRemove { + link, + validation_data, + } => { + // get author of this entry + let author = validation_data.package.chain_header.provenances()[0].source(); + // get link base: entry from which the link goes + let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + if author != base.teacher_address { + return Err(String::from( + "Can't remove link from CourseAnchor to Course because your address isn't specified as teacher_address for this course", + )); + } + Ok(()) + } + } +} diff --git a/dna/course/zomes/courses/code/src/section/entry.rs b/dna/course/zomes/courses/code/src/section/entry.rs index ebed85b..60e834b 100644 --- a/dna/course/zomes/courses/code/src/section/entry.rs +++ b/dna/course/zomes/courses/code/src/section/entry.rs @@ -45,18 +45,15 @@ pub fn entry_def() -> ValidatingEntryType { hdk::ValidationPackageDefinition::Entry }, validation: | validation_data: hdk::EntryValidationData
| { - match validation_data { - EntryValidationData::Create { .. } => { - // TODO: implement validation - Ok(()) + match validation_data { + EntryValidationData::Create { entry, validation_data } => { + validation::create(entry, validation_data) }, - EntryValidationData::Modify { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Modify { new_entry, old_entry, old_entry_header, validation_data } => { + validation::modify(new_entry, old_entry, old_entry_header, validation_data) }, - EntryValidationData::Delete { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Delete { old_entry, old_entry_header, validation_data } => { + validation::delete(old_entry, old_entry_header, validation_data) } } }, diff --git a/dna/course/zomes/courses/code/src/section/validation.rs b/dna/course/zomes/courses/code/src/section/validation.rs new file mode 100644 index 0000000..e05cda1 --- /dev/null +++ b/dna/course/zomes/courses/code/src/section/validation.rs @@ -0,0 +1,151 @@ +/* +use super::{ + anchor::CourseAnchor, + catalog_anchor::CourseCatalogAnchor, + entry::{Course, MAX_TITLE_LEN}, +}; +use crate::anchor_trait::AnchorTrait; +use crate::helper; +use hdk::holochain_core_types::chain_header::ChainHeader; +use hdk::{LinkValidationData, ValidationData}; +use holochain_entry_utils::HolochainEntry; + +pub fn create(entry: Course, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "create their courses", + )?; + helper::validate_entity_title(&entry.title, &Course::entry_type(), MAX_TITLE_LEN) +} + +pub fn modify( + new_entry: Course, + old_entry: Course, + _old_entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &old_entry.teacher_address, + validation_data.sources(), + "modify their courses", + )?; + helper::validate_entity_title(&new_entry.title, &Course::entry_type(), MAX_TITLE_LEN)?; + validate_no_teacher_change(old_entry, new_entry) +} + +// this fn is only needed in the current module so it's private +fn validate_no_teacher_change(old_entry: Course, new_entry: Course) -> Result<(), String> { + if new_entry.teacher_address != old_entry.teacher_address { + return Err(String::from("Cannot change the teacher of the course")); + } + Ok(()) +} + +pub fn delete( + entry: Course, + _entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "delete their courses", + ) +} + +// =========================== CourseAnchor validation +pub fn anchor_create(entry: CourseAnchor, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "create their courses", + )?; + helper::validate_entity_title(&entry.title, &CourseAnchor::entry_type(), MAX_TITLE_LEN) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be modified +pub fn anchor_modify() -> Result<(), String> { + Err(String::from( + "Can't modify the CourseAnchor entry: it can only be created or deleted", + )) +} + +pub fn anchor_delete( + entry: CourseAnchor, + _entry_header: ChainHeader, + validation_data: ValidationData, +) -> Result<(), String> { + helper::validate_only_teacher_can_do( + &entry.teacher_address, + validation_data.sources(), + "delete their courses", + ) +} + +// =========================== CourseCatalogAnchor validation +// Anyone can create the CourseCatalogAnchor and there isn't anything we need to validate about it +pub fn catalog_create( + _entry: CourseCatalogAnchor, + _validation_data: ValidationData, +) -> Result<(), String> { + Ok(()) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be modified +pub fn catalog_modify() -> Result<(), String> { + Err(String::from("Can't modify the CourseAnchorCatalog entry")) +} + +// NOTE: we don't accept any parameters here because we don't need them to always return an error +// because this anchor can never be deleted +pub fn catalog_delete() -> Result<(), String> { + Err(String::from("Can't delete the CourseAnchorCatalog entry")) +} + +// =========================== CourseAnchor links validation + +pub fn anchor_to_course_link(validation_data: LinkValidationData) -> Result<(), String> { + match validation_data { + hdk::LinkValidationData::LinkAdd { + link, + validation_data, + } => { + // get author of this entry + let author = validation_data.package.chain_header.provenances()[0].source(); + // get link base: entry from which the link goes + let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + // get link target: entry to which the link goes + let target: Course = hdk::utils::get_as_type(link.link.target().clone())?; + if base.teacher_address != target.teacher_address { + // notice that we're using return and ending this statement with ; symbol + // You can do both: skip ; symbol in the last fn statement or explicitly add return to it and then leave ; as is + return Err(String::from( + "Can't link CourseAnchor to Course because their teacher addresses are different", + )); + } else if author != base.teacher_address { + return Err(String::from( + "Can't link CourseAnchor to Course because your address isn't specified as teacher address for this course", + )); + } + Ok(()) + } + hdk::LinkValidationData::LinkRemove { + link, + validation_data, + } => { + // get author of this entry + let author = validation_data.package.chain_header.provenances()[0].source(); + // get link base: entry from which the link goes + let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + if author != base.teacher_address { + return Err(String::from( + "Can't remove link from CourseAnchor to Course because your address isn't specified as teacher_address for this course", + )); + } + Ok(()) + } + } +} From a11d732d8580c371ff40cac616881371d1d15862 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 20 Aug 2020 20:42:05 +0100 Subject: [PATCH 6/8] Section anchor validation rules --- .../zomes/courses/code/src/section/anchor.rs | 19 +++++++++---------- .../courses/code/src/section/validation.rs | 5 ++--- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/dna/course/zomes/courses/code/src/section/anchor.rs b/dna/course/zomes/courses/code/src/section/anchor.rs index 4dac6b6..5e6a7fa 100644 --- a/dna/course/zomes/courses/code/src/section/anchor.rs +++ b/dna/course/zomes/courses/code/src/section/anchor.rs @@ -48,17 +48,16 @@ pub fn section_anchor_def() -> ValidatingEntryType { }, validation: | validation_data: hdk::EntryValidationData| { match validation_data{ - EntryValidationData::Create { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Create { entry, validation_data } => { + validation::anchor_create(entry, validation_data) }, + // NOTE: the symbol .. means that we're skipping unpacking parameters that we receive here + // because we won't need them EntryValidationData::Modify { .. } => { - // TODO: implement validation - Ok(()) + validation::anchor_modify() }, - EntryValidationData::Delete { .. } => { - // TODO: implement validation - Ok(()) + EntryValidationData::Delete { old_entry, old_entry_header, validation_data } => { + validation::anchor_delete(old_entry, old_entry_header, validation_data) } } }, @@ -69,8 +68,8 @@ pub fn section_anchor_def() -> ValidatingEntryType { validation_package:||{ hdk::ValidationPackageDefinition::Entry }, - validation:|_validation_data: hdk::LinkValidationData|{ - Ok(()) + validation:|validation_data: hdk::LinkValidationData|{ + validation::anchor_to_section_link(validation_data) } ), to!( diff --git a/dna/course/zomes/courses/code/src/section/validation.rs b/dna/course/zomes/courses/code/src/section/validation.rs index e05cda1..9719531 100644 --- a/dna/course/zomes/courses/code/src/section/validation.rs +++ b/dna/course/zomes/courses/code/src/section/validation.rs @@ -1,4 +1,3 @@ -/* use super::{ anchor::CourseAnchor, catalog_anchor::CourseCatalogAnchor, @@ -105,9 +104,9 @@ pub fn catalog_delete() -> Result<(), String> { Err(String::from("Can't delete the CourseAnchorCatalog entry")) } -// =========================== CourseAnchor links validation +// =========================== SectionAnchor links validation -pub fn anchor_to_course_link(validation_data: LinkValidationData) -> Result<(), String> { +pub fn anchor_to_section_link(validation_data: LinkValidationData) -> Result<(), String> { match validation_data { hdk::LinkValidationData::LinkAdd { link, From 4ef00a2a6e0ec2e10a4a4ad1b11544d1d86965ee Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 21 Aug 2020 19:12:13 +0100 Subject: [PATCH 7/8] Section validation rules long form --- .../courses/code/src/section/validation.rs | 87 ++++++++----------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/dna/course/zomes/courses/code/src/section/validation.rs b/dna/course/zomes/courses/code/src/section/validation.rs index 9719531..f0ecb1a 100644 --- a/dna/course/zomes/courses/code/src/section/validation.rs +++ b/dna/course/zomes/courses/code/src/section/validation.rs @@ -1,7 +1,9 @@ +//modify me with correct pointers + use super::{ - anchor::CourseAnchor, - catalog_anchor::CourseCatalogAnchor, - entry::{Course, MAX_TITLE_LEN}, + anchor::SectionAnchor, + catalog_anchor::CourseCatalogAnchor, //I feel this is probably not needed + entry::{Section, MAX_TITLE_LEN}, //MAX_Title should probably go as well, should entry though? }; use crate::anchor_trait::AnchorTrait; use crate::helper; @@ -9,101 +11,80 @@ use hdk::holochain_core_types::chain_header::ChainHeader; use hdk::{LinkValidationData, ValidationData}; use holochain_entry_utils::HolochainEntry; -pub fn create(entry: Course, validation_data: ValidationData) -> Result<(), String> { - helper::validate_only_teacher_can_do( +pub fn create(entry: Section, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( //can only teachers create sections? If so good, else probably dont need this helper &entry.teacher_address, validation_data.sources(), - "create their courses", + "create course setions", )?; - helper::validate_entity_title(&entry.title, &Course::entry_type(), MAX_TITLE_LEN) + helper::validate_entity_title(&entry.title, &Section::entry_type()) //no need for title length here I guess } pub fn modify( - new_entry: Course, - old_entry: Course, + new_entry: Section, + old_entry: Section, _old_entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { - helper::validate_only_teacher_can_do( + helper::validate_only_teacher_can_do( //same as above, if needed cool - if not this should not be needed &old_entry.teacher_address, validation_data.sources(), - "modify their courses", + "modify their sections", )?; - helper::validate_entity_title(&new_entry.title, &Course::entry_type(), MAX_TITLE_LEN)?; - validate_no_teacher_change(old_entry, new_entry) + helper::validate_entity_title(&new_entry.title, &Section::entry_type())?; + validate_no_teacher_change(old_entry, new_entry) //if teachers matter } // this fn is only needed in the current module so it's private -fn validate_no_teacher_change(old_entry: Course, new_entry: Course) -> Result<(), String> { +fn validate_no_teacher_change(old_entry: Section, new_entry: Section) -> Result<(), String> { if new_entry.teacher_address != old_entry.teacher_address { - return Err(String::from("Cannot change the teacher of the course")); + return Err(String::from("Cannot change the teacher of the Section")); } Ok(()) } pub fn delete( - entry: Course, + entry: Section, _entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { - helper::validate_only_teacher_can_do( + helper::validate_only_teacher_can_do(//unless students can create sections in which case this rule goes &entry.teacher_address, validation_data.sources(), - "delete their courses", + "delete their Sections", ) } -// =========================== CourseAnchor validation -pub fn anchor_create(entry: CourseAnchor, validation_data: ValidationData) -> Result<(), String> { +// =========================== SectionAnchor validation +pub fn anchor_create(entry: SectionAnchor, validation_data: ValidationData) -> Result<(), String> { helper::validate_only_teacher_can_do( &entry.teacher_address, validation_data.sources(), - "create their courses", + "create their sections", )?; - helper::validate_entity_title(&entry.title, &CourseAnchor::entry_type(), MAX_TITLE_LEN) + helper::validate_entity_title(&entry.title, &SectionAnchor::entry_type()) //deleted max_title as theres no max entry in the anchor code.. propably no title anyway, its an anchor } // NOTE: we don't accept any parameters here because we don't need them to always return an error // because this anchor can never be modified pub fn anchor_modify() -> Result<(), String> { Err(String::from( - "Can't modify the CourseAnchor entry: it can only be created or deleted", + "Can't modify the SectionAnchor entry: it can only be created or deleted", )) } pub fn anchor_delete( - entry: CourseAnchor, + entry: SectionAnchor, _entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { - helper::validate_only_teacher_can_do( + helper::validate_only_teacher_can_do(//teachers only CRUD sections assumption still &entry.teacher_address, validation_data.sources(), - "delete their courses", + "delete their section anchor", ) } -// =========================== CourseCatalogAnchor validation -// Anyone can create the CourseCatalogAnchor and there isn't anything we need to validate about it -pub fn catalog_create( - _entry: CourseCatalogAnchor, - _validation_data: ValidationData, -) -> Result<(), String> { - Ok(()) -} - -// NOTE: we don't accept any parameters here because we don't need them to always return an error -// because this anchor can never be modified -pub fn catalog_modify() -> Result<(), String> { - Err(String::from("Can't modify the CourseAnchorCatalog entry")) -} - -// NOTE: we don't accept any parameters here because we don't need them to always return an error -// because this anchor can never be deleted -pub fn catalog_delete() -> Result<(), String> { - Err(String::from("Can't delete the CourseAnchorCatalog entry")) -} - // =========================== SectionAnchor links validation pub fn anchor_to_section_link(validation_data: LinkValidationData) -> Result<(), String> { @@ -115,18 +96,18 @@ pub fn anchor_to_section_link(validation_data: LinkValidationData) -> Result<(), // get author of this entry let author = validation_data.package.chain_header.provenances()[0].source(); // get link base: entry from which the link goes - let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + let base: SectionAnchor = hdk::utils::get_as_type(link.link.base().clone())?; // get link target: entry to which the link goes - let target: Course = hdk::utils::get_as_type(link.link.target().clone())?; + let target: Section = hdk::utils::get_as_type(link.link.target().clone())?; if base.teacher_address != target.teacher_address { // notice that we're using return and ending this statement with ; symbol // You can do both: skip ; symbol in the last fn statement or explicitly add return to it and then leave ; as is return Err(String::from( - "Can't link CourseAnchor to Course because their teacher addresses are different", + "Can't link SectionAnchor to Section because their teacher addresses are different", )); } else if author != base.teacher_address { return Err(String::from( - "Can't link CourseAnchor to Course because your address isn't specified as teacher address for this course", + "Can't link SectionAnchor to Section because your address isn't specified as teacher address for this Section", )); } Ok(()) @@ -138,10 +119,10 @@ pub fn anchor_to_section_link(validation_data: LinkValidationData) -> Result<(), // get author of this entry let author = validation_data.package.chain_header.provenances()[0].source(); // get link base: entry from which the link goes - let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; + let base: SectionAnchor = hdk::utils::get_as_type(link.link.base().clone())?; if author != base.teacher_address { return Err(String::from( - "Can't remove link from CourseAnchor to Course because your address isn't specified as teacher_address for this course", + "Can't remove link from SectionAnchor to Section because your address isn't specified as teacher_address for this Section", )); } Ok(()) From 2c3e36be3c8e41e969595c14b743f76bab146e35 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 21 Aug 2020 19:29:51 +0100 Subject: [PATCH 8/8] Contet validation rules long form --- .../courses/code/src/content/validation.rs | 116 ++++-------------- .../courses/code/src/section/validation.rs | 2 - 2 files changed, 25 insertions(+), 93 deletions(-) diff --git a/dna/course/zomes/courses/code/src/content/validation.rs b/dna/course/zomes/courses/code/src/content/validation.rs index 2b8f9a3..ea014a1 100644 --- a/dna/course/zomes/courses/code/src/content/validation.rs +++ b/dna/course/zomes/courses/code/src/content/validation.rs @@ -1,68 +1,67 @@ -/* - -use super::{ - anchor::CourseAnchor, - catalog_anchor::CourseCatalogAnchor, - entry::{Course, MAX_TITLE_LEN}, -}; +use super::{ //Ummmm above should all probably get deleted but since content is linked to section anchor I've made changes. Also I feel like super is the wrong "expression" for retrieving section anchor as its in another directory + anchor::SectionAnchor, + entry::{Content}, +}; use crate::anchor_trait::AnchorTrait; use crate::helper; use hdk::holochain_core_types::chain_header::ChainHeader; use hdk::{LinkValidationData, ValidationData}; use holochain_entry_utils::HolochainEntry; -pub fn create(entry: Course, validation_data: ValidationData) -> Result<(), String> { - helper::validate_only_teacher_can_do( +pub fn create(entry: Content, validation_data: ValidationData) -> Result<(), String> { + helper::validate_only_teacher_can_do( //only teachers to create content? &entry.teacher_address, validation_data.sources(), "create their courses", )?; - helper::validate_entity_title(&entry.title, &Course::entry_type(), MAX_TITLE_LEN) + helper::validate_entity_title(&entry.title, &Content::entry_type()) } pub fn modify( - new_entry: Course, - old_entry: Course, + new_entry: Content, + old_entry: Content, _old_entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { - helper::validate_only_teacher_can_do( + helper::validate_only_teacher_can_do( //teachers only assumption, else delete rule &old_entry.teacher_address, validation_data.sources(), - "modify their courses", + "modify their content", )?; - helper::validate_entity_title(&new_entry.title, &Course::entry_type(), MAX_TITLE_LEN)?; + helper::validate_entity_title(&new_entry.title, &Course::entry_type())?; validate_no_teacher_change(old_entry, new_entry) } // this fn is only needed in the current module so it's private -fn validate_no_teacher_change(old_entry: Course, new_entry: Course) -> Result<(), String> { +fn validate_no_teacher_change(old_entry: Content, new_entry: Contetnt) -> Result<(), String> { if new_entry.teacher_address != old_entry.teacher_address { - return Err(String::from("Cannot change the teacher of the course")); + return Err(String::from("Cannot change the teacher of the content")); } Ok(()) } pub fn delete( - entry: Course, + entry: Content, _entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { helper::validate_only_teacher_can_do( &entry.teacher_address, validation_data.sources(), - "delete their courses", + "delete their content", ) } -// =========================== CourseAnchor validation -pub fn anchor_create(entry: CourseAnchor, validation_data: ValidationData) -> Result<(), String> { +// =========================== ContentAnchor validation +/* Pointers changed to direct to the section anchor, though I reckon its an unnecessary section hence commenting it out + +pub fn anchor_create(entry: SectionAnchor, validation_data: ValidationData) -> Result<(), String> { helper::validate_only_teacher_can_do( &entry.teacher_address, validation_data.sources(), - "create their courses", + "create their content", )?; - helper::validate_entity_title(&entry.title, &CourseAnchor::entry_type(), MAX_TITLE_LEN) + helper::validate_entity_title(&entry.title, &SectionAnchor::entry_type()) } // NOTE: we don't accept any parameters here because we don't need them to always return an error @@ -74,79 +73,14 @@ pub fn anchor_modify() -> Result<(), String> { } pub fn anchor_delete( - entry: CourseAnchor, + entry: SectionAnchor, _entry_header: ChainHeader, validation_data: ValidationData, ) -> Result<(), String> { helper::validate_only_teacher_can_do( &entry.teacher_address, validation_data.sources(), - "delete their courses", + "delete their content", ) } - -// =========================== CourseCatalogAnchor validation -// Anyone can create the CourseCatalogAnchor and there isn't anything we need to validate about it -pub fn catalog_create( - _entry: CourseCatalogAnchor, - _validation_data: ValidationData, -) -> Result<(), String> { - Ok(()) -} - -// NOTE: we don't accept any parameters here because we don't need them to always return an error -// because this anchor can never be modified -pub fn catalog_modify() -> Result<(), String> { - Err(String::from("Can't modify the CourseAnchorCatalog entry")) -} - -// NOTE: we don't accept any parameters here because we don't need them to always return an error -// because this anchor can never be deleted -pub fn catalog_delete() -> Result<(), String> { - Err(String::from("Can't delete the CourseAnchorCatalog entry")) -} - -// =========================== CourseAnchor links validation - -pub fn anchor_to_course_link(validation_data: LinkValidationData) -> Result<(), String> { - match validation_data { - hdk::LinkValidationData::LinkAdd { - link, - validation_data, - } => { - // get author of this entry - let author = validation_data.package.chain_header.provenances()[0].source(); - // get link base: entry from which the link goes - let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; - // get link target: entry to which the link goes - let target: Course = hdk::utils::get_as_type(link.link.target().clone())?; - if base.teacher_address != target.teacher_address { - // notice that we're using return and ending this statement with ; symbol - // You can do both: skip ; symbol in the last fn statement or explicitly add return to it and then leave ; as is - return Err(String::from( - "Can't link CourseAnchor to Course because their teacher addresses are different", - )); - } else if author != base.teacher_address { - return Err(String::from( - "Can't link CourseAnchor to Course because your address isn't specified as teacher address for this course", - )); - } - Ok(()) - } - hdk::LinkValidationData::LinkRemove { - link, - validation_data, - } => { - // get author of this entry - let author = validation_data.package.chain_header.provenances()[0].source(); - // get link base: entry from which the link goes - let base: CourseAnchor = hdk::utils::get_as_type(link.link.base().clone())?; - if author != base.teacher_address { - return Err(String::from( - "Can't remove link from CourseAnchor to Course because your address isn't specified as teacher_address for this course", - )); - } - Ok(()) - } - } -} +*/ \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/section/validation.rs b/dna/course/zomes/courses/code/src/section/validation.rs index f0ecb1a..af6fc4f 100644 --- a/dna/course/zomes/courses/code/src/section/validation.rs +++ b/dna/course/zomes/courses/code/src/section/validation.rs @@ -1,5 +1,3 @@ -//modify me with correct pointers - use super::{ anchor::SectionAnchor, catalog_anchor::CourseCatalogAnchor, //I feel this is probably not needed