diff --git a/dna/course/zomes/courses/code/src/anchor_trait.rs b/dna/course/zomes/courses/code/src/anchor_trait.rs new file mode 100644 index 0000000..a552de9 --- /dev/null +++ b/dna/course/zomes/courses/code/src/anchor_trait.rs @@ -0,0 +1,16 @@ +use hdk::prelude::*; +use std::convert::TryFrom; + +// thanks to @HedayatAbedijoo for this trait +pub trait AnchorTrait: TryFrom + Into + Clone { + fn entry_type() -> String; + fn link_to() -> String; + fn link_type() -> String; + fn entry(self) -> Entry { + Entry::App(Self::entry_type().into(), self.into()) + } + + fn address(&self) -> ZomeApiResult
{ + hdk::entry_address(&self.clone().entry()) + } +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/course/anchor.rs b/dna/course/zomes/courses/code/src/course/anchor.rs new file mode 100644 index 0000000..0c4c2b1 --- /dev/null +++ b/dna/course/zomes/courses/code/src/course/anchor.rs @@ -0,0 +1,114 @@ +use hdk::prelude::*; +use holochain_entry_utils::HolochainEntry; + +use super::entry::Course; +use crate::anchor_trait::AnchorTrait; + +pub const TEACHER_TO_COURSE_ANCHOR_LINK: &str = "teacher->course_anchor"; +pub const STUDENT_TO_COURSE_ANCHOR_LINK: &str = "student->course_anchor"; +pub const COURSE_ANCHOR_TO_STUDENT_LINK: &str = "course_anchor->student"; + +#[derive(Serialize, Deserialize, Debug, self::DefaultJson, Clone)] +pub struct CourseAnchor { + // NOTE: these fields are here to ensure the uniqueness of every particular anchor + // and wouldn't be used to display data about course to a user + pub title: String, + pub teacher_address: Address, + pub timestamp: u64, +} + +impl AnchorTrait for CourseAnchor { + fn entry_type() -> String { + String::from("course_anchor") + } + fn link_to() -> String { + Course::entry_type() + } + fn link_type() -> String { + "course_anchor->course".to_owned() + } +} + +impl CourseAnchor { + pub fn new(title: String, teacher_address: Address, timestamp: u64) -> Self { + CourseAnchor { + title: title, + teacher_address: teacher_address, + timestamp: timestamp, + } + } +} + +pub fn course_anchor_def() -> ValidatingEntryType { + entry!( + name: CourseAnchor::entry_type(), + description: "Anchor to the valid course", + sharing: Sharing::Public, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | validation_data: hdk::EntryValidationData| { + match validation_data{ + EntryValidationData::Create { .. } => { + Ok(()) + }, + EntryValidationData::Modify { .. } => { + Ok(()) + }, + EntryValidationData::Delete { .. } => { + Ok(()) + } + } + }, + links:[ + // link that connects CourseAnchor to the latest Course entry + // This is a necessary link that allows access to course data + to!( + CourseAnchor::link_to(), + link_type: CourseAnchor::link_type(), + validation_package:||{ + hdk::ValidationPackageDefinition::Entry + }, + validation:|_validation_data: hdk::LinkValidationData|{ + Ok(()) + } + ), + // link from agent that is a teacher of this course + // This is for teacher to keep track of all the courses that they're teaching + from!( + "%agent_id", // this is a special string that would automatically expand to the hdk::AGENT_ADDRESS + link_type: TEACHER_TO_COURSE_ANCHOR_LINK, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + } , + validation: | _validation_data: hdk::LinkValidationData | { + Ok(()) + } + ), + // link from agent that is a student who enrolled in this course + // This is for student to keep track of all the courses they've enrolled in + from!( + "%agent_id", // this is a special string that would automatically expand to the hdk::AGENT_ADDRESS + link_type: STUDENT_TO_COURSE_ANCHOR_LINK, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + } , + validation: | _validation_data: hdk::LinkValidationData | { + Ok(()) + } + ), + // link to an agent who is a student enrolled in this course. + // This is to keep track of student list from the course perspective + to!( + "%agent_id", // this is a special string that would automatically expand to the hdk::AGENT_ADDRESS + link_type: COURSE_ANCHOR_TO_STUDENT_LINK, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | _validation_data: hdk::LinkValidationData | { + Ok(()) + } + ) + ] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/course/catalogue_anchor.rs b/dna/course/zomes/courses/code/src/course/catalogue_anchor.rs new file mode 100644 index 0000000..0d96df7 --- /dev/null +++ b/dna/course/zomes/courses/code/src/course/catalogue_anchor.rs @@ -0,0 +1,59 @@ +use hdk::prelude::*; +use hdk::{entry_definition::ValidatingEntryType, holochain_core_types::dna::entry_types::Sharing}; + +use super::anchor::CourseAnchor; +use crate::anchor_trait::AnchorTrait; + +#[derive(Serialize, Deserialize, Debug, self::DefaultJson, Clone)] +pub struct CourseCatalogAnchor { + name: String, +} + +impl AnchorTrait for CourseCatalogAnchor { + fn entry_type() -> String { + String::from("course_catalog_anchor") + } + fn link_to() -> String { + CourseAnchor::entry_type() + } + fn link_type() -> String { + // NOTE: ideas for a better name for this link are welcome! + // there'll be a single link per every course + "course_list".to_owned() + } +} + +impl CourseCatalogAnchor { + pub fn new() -> Self { + CourseCatalogAnchor { + name: CourseCatalogAnchor::entry_type(), + } + } +} + +//// Anchor Definition : This Anchor will be used to query all courses +pub fn catalog_anchor_entry_def() -> ValidatingEntryType { + entry!( + name: CourseCatalogAnchor::entry_type(), + description:"Anchor that serves as a catalog for all Course entries", + sharing: Sharing::Public, + validation_package:||{ + hdk::ValidationPackageDefinition::Entry + }, + validation:|_validation_data: hdk::EntryValidationData|{ + Ok(()) + }, + links:[ + to!( + CourseCatalogAnchor::link_to(), + link_type: CourseCatalogAnchor::link_type(), + validation_package:||{ + hdk::ValidationPackageDefinition::Entry + }, + validation:|_validation_data: hdk::LinkValidationData|{ + Ok(()) + } + ) + ] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/course/entry.rs b/dna/course/zomes/courses/code/src/course/entry.rs new file mode 100644 index 0000000..a638b5a --- /dev/null +++ b/dna/course/zomes/courses/code/src/course/entry.rs @@ -0,0 +1,67 @@ +use hdk::{ + entry_definition::ValidatingEntryType, + holochain_core_types::{dna::entry_types::Sharing, validation::EntryValidationData}, + holochain_json_api::{error::JsonError, json::JsonString}, + holochain_persistence_api::cas::content::Address, +}; +use holochain_entry_utils::HolochainEntry; + +#[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] +pub struct Course { + pub title: String, + pub sections: Vec
, + pub teacher_address: Address, + pub timestamp: u64, + pub anchor_address: Address, +} + +impl HolochainEntry for Course { + fn entry_type() -> String { + String::from("course") + } +} + +impl Course { + pub fn new( + title: String, + sections: Vec
, + teacher_address: Address, + timestamp: u64, + anchor_address: Address, + ) -> Self { + Course { + title: title, + sections: sections, + teacher_address: teacher_address, + timestamp: timestamp, + anchor_address: anchor_address, + } + } +} + +// Holochain entry definition for Course +pub fn course_entry_def() -> ValidatingEntryType { + entry!( + name: Course::entry_type(), + description: "this is the definition of course", + sharing: Sharing::Public, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | validation_data: hdk::EntryValidationData| { + match validation_data { + EntryValidationData::Create { .. } => { + Ok(()) + }, + EntryValidationData::Modify { .. } => { + Ok(()) + }, + EntryValidationData::Delete { .. } => { + Ok(()) + } + } + }, + // All links that course should have are defined for CoureAnchor and so this entry doesn't have any + links: [] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/course/mod.rs b/dna/course/zomes/courses/code/src/course/mod.rs new file mode 100644 index 0000000..24a2a35 --- /dev/null +++ b/dna/course/zomes/courses/code/src/course/mod.rs @@ -0,0 +1,3 @@ +pub mod anchor; +pub mod catalog_anchor; +pub mod entry; \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/lib.rs b/dna/course/zomes/courses/code/src/lib.rs index c4cc8ff..56828e7 100644 --- a/dna/course/zomes/courses/code/src/lib.rs +++ b/dna/course/zomes/courses/code/src/lib.rs @@ -1,55 +1,76 @@ +// allowing for this Rust project to have dead code on a crate level +#![allow(dead_code)] +// unstable Rust feature +// See more at: https://doc.rust-lang.org/nightly/unstable-book/language-features/proc-macro-hygiene.html #![feature(proc_macro_hygiene)] +// This isn't a mistake that there are multiple #[macro_use] below: each applies to a particular crate that follows it +// specifying that we want to import macros defined in this crate too. +// See more at: https://doc.rust-lang.org/reference/macros-by-example.html +#[macro_use] +extern crate hdk; +extern crate hdk_proc_macros; +extern crate serde; +#[macro_use] +extern crate serde_derive; +extern crate serde_json; +#[macro_use] +extern crate holochain_json_derive; use hdk::prelude::*; -use hdk_proc_macros::zome; - -// see https://developer.holochain.org/api/0.0.50-alpha4/hdk/ for info on using the hdk library -// This is a sample zome that defines an entry type "MyEntry" that can be committed to the -// agent's chain via the exposed function create_my_entry +use hdk_proc_macros::zome; -#[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] -pub struct MyEntry { - content: String, -} +mod anchor_trait; +mod course; #[zome] -mod my_zome { +mod courses { + // Things to be done on an hApp init, we skip this for now #[init] fn init() { Ok(()) } + // Things to be done to validate each agent in the network, we skip this for now #[validate_agent] pub fn validate_agent(validation_data: EntryValidationData) { Ok(()) } + // ====================== Course definitions (methods!) + #[entry_def] + fn course_catalog_anchor_entry_definition() -> ValidatingEntryType { + course::catalog_anchor::catalog_anchor_entry_def() + } + #[entry_def] - fn my_entry_def() -> ValidatingEntryType { - entry!( - name: "my_entry", - description: "this is a same entry defintion", - sharing: Sharing::Public, - validation_package: || { - hdk::ValidationPackageDefinition::Entry - }, - validation: | _validation_data: hdk::EntryValidationData| { - Ok(()) - } - ) - } - - #[zome_fn("hc_public")] - fn create_my_entry(entry: MyEntry) -> ZomeApiResult
{ - let entry = Entry::App("my_entry".into(), entry.into()); - let address = hdk::commit_entry(&entry)?; - Ok(address) - } - - #[zome_fn("hc_public")] - fn get_my_entry(address: Address) -> ZomeApiResult> { - hdk::get_entry(&address) - } -} + fn course_anchor_definition() -> ValidatingEntryType { + course::anchor::course_anchor_def() + } + + #[entry_def] + fn course_entry_definition() -> ValidatingEntryType { + course::entry::course_entry_def() + } + + // Section + // TODO: implement section entry definitions + #[entry_def] + fn section_entry_definition() -> ValidatingEntryType { + section::entry::section_entry_def() + } + //new + #[entry_def] + fn section_anchor_definition() -> ValidatingEntryType { + section::entry::section_anchor_def() + } + + // Content + // TODO: implement content entry definition + #[entry_def] + fn content_entry_definition() -> ValidatingEntryType { + section::entry::content_entry_def() + } + +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/section/anchor.rs b/dna/course/zomes/courses/code/src/section/anchor.rs new file mode 100644 index 0000000..e2aaea4 --- /dev/null +++ b/dna/course/zomes/courses/code/src/section/anchor.rs @@ -0,0 +1,61 @@ +use hdk::prelude::*; +use holochain_entry_utils::HolochainEntry; + +use super::entry::Section; +use crate::anchor_trait::AnchorTrait; + +#[derive(Serialize, Deserialize, Debug, self::DefaultJson, Clone)] +pub struct SectionAnchor { + // NOTE: these fields are here to ensure the uniqueness of every particular anchor + // and wouldn't be used to display data about course to a user + pub title: String, + pub teacher_address: Address, + pub timestamp: u64, +} + +impl AnchorTrait for SectionAnchor { + fn entry_type() -> String { + String::from("section_anchor") + } + fn link_to() -> String { + Section::entry_type() + } + fn link_type() -> String { + "section_anchor->section".to_owned() + } +} + +impl SectionAnchor { + pub fn new(title: String, teacher_address: Address, timestamp: u64) -> Self { + SectionAnchor { + title: title, + teacher_address: teacher_address, + timestamp: timestamp, + } + } +} + +pub fn section_anchor_def() -> ValidatingEntryType { + entry!( + name: SectionAnchor::entry_type(), + description: "Anchor to the valid section", + sharing: Sharing::Public, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | validation_data: hdk::EntryValidationData| { + match validation_data{ + EntryValidationData::Create { .. } => { + Ok(()) + }, + EntryValidationData::Modify { .. } => { + Ok(()) + }, + EntryValidationData::Delete { .. } => { + Ok(()) + } + } + }, + links:[] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/section/content.rs b/dna/course/zomes/courses/code/src/section/content.rs new file mode 100644 index 0000000..01a9470 --- /dev/null +++ b/dna/course/zomes/courses/code/src/section/content.rs @@ -0,0 +1,67 @@ +use hdk::{ + entry_definition::ValidatingEntryType, + holochain_core_types::{dna::entry_types::Sharing, validation::EntryValidationData}, + holochain_json_api::{error::JsonError, json::JsonString}, + holochain_persistence_api::cas::content::Address, +}; +use holochain_entry_utils::HolochainEntry; + +#[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] +pub struct Content { + pub title: String, + pub sections: Vec
, + pub teacher_address: Address, + pub timestamp: u64, + pub anchor_address: Address, +} + +impl HolochainEntry for Content { + fn entry_type() -> String { + String::from("content") + } +} + +impl Content { + pub fn new( + title: String, + sections: Vec
, + teacher_address: Address, + timestamp: u64, + anchor_address: Address, + ) -> Self { + Content { + title: title, + sections: sections, + teacher_address: teacher_address, + timestamp: timestamp, + anchor_address: anchor_address, + } + } +} + +// Holochain entry definition for Content +pub fn section_entry_def() -> ValidatingEntryType { + entry!( + name: Section::entry_type(), + description: "this is the definition of content", + sharing: Sharing::Public, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | validation_data: hdk::EntryValidationData| { + match validation_data { + EntryValidationData::Create { .. } => { + Ok(()) + }, + EntryValidationData::Modify { .. } => { + Ok(()) + }, + EntryValidationData::Delete { .. } => { + Ok(()) + } + } + }, + // All links that course should have are defined for sectiion anchor and so this entry doesn't have any + links: [] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/section/entry.rs b/dna/course/zomes/courses/code/src/section/entry.rs new file mode 100644 index 0000000..2a6c2c2 --- /dev/null +++ b/dna/course/zomes/courses/code/src/section/entry.rs @@ -0,0 +1,67 @@ +use hdk::{ + entry_definition::ValidatingEntryType, + holochain_core_types::{dna::entry_types::Sharing, validation::EntryValidationData}, + holochain_json_api::{error::JsonError, json::JsonString}, + holochain_persistence_api::cas::content::Address, +}; +use holochain_entry_utils::HolochainEntry; + +#[derive(Serialize, Deserialize, Debug, DefaultJson, Clone)] +pub struct Section { + pub title: String, + pub sections: Vec
, + pub teacher_address: Address, + pub timestamp: u64, + pub anchor_address: Address, +} + +impl HolochainEntry for Section { + fn entry_type() -> String { + String::from("section") + } +} + +impl Section { + pub fn new( + title: String, + sections: Vec
, + teacher_address: Address, + timestamp: u64, + anchor_address: Address, + ) -> Self { + Section { + title: title, + sections: sections, + teacher_address: teacher_address, + timestamp: timestamp, + anchor_address: anchor_address, + } + } +} + +// Holochain entry definition for Course +pub fn section_entry_def() -> ValidatingEntryType { + entry!( + name: Section::entry_type(), + description: "this is the definition of section", + sharing: Sharing::Public, + validation_package: || { + hdk::ValidationPackageDefinition::Entry + }, + validation: | validation_data: hdk::EntryValidationData| { + match validation_data { + EntryValidationData::Create { .. } => { + Ok(()) + }, + EntryValidationData::Modify { .. } => { + Ok(()) + }, + EntryValidationData::Delete { .. } => { + Ok(()) + } + } + }, + // All links that course should have are defined for CoureAnchor and so this entry doesn't have any + links: [] + ) +} \ No newline at end of file diff --git a/dna/course/zomes/courses/code/src/section/mod.rs b/dna/course/zomes/courses/code/src/section/mod.rs new file mode 100644 index 0000000..621f180 --- /dev/null +++ b/dna/course/zomes/courses/code/src/section/mod.rs @@ -0,0 +1,3 @@ +pub mod anchor; +pub mod content; +pub mod entry; \ No newline at end of file