notes/
note.rs

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use hdk::prelude::*;
use notes_integrity::*;

#[hdk_extern]
pub fn create_note(note: Note) -> ExternResult<Record> {
    let note_hash = create_entry(&EntryTypes::Note(note.clone()))?;
    let record = get(note_hash.clone(), GetOptions::default())?.ok_or(wasm_error!(
        WasmErrorInner::Guest("Could not find the newly created Note".to_string())
    ))?;
    let path = Path::from("all_notes");
    create_link(
        path.path_entry_hash()?,
        note_hash.clone(),
        LinkTypes::AllNotes,
        (),
    )?;
    Ok(record)
}

#[hdk_extern]
pub fn get_latest_note(original_note_hash: ActionHash) -> ExternResult<Option<Record>> {
    let links = get_links(
        GetLinksInputBuilder::try_new(original_note_hash.clone(), LinkTypes::NoteUpdates)?.build(),
    )?;
    let latest_link = links
        .into_iter()
        .max_by(|link_a, link_b| link_a.timestamp.cmp(&link_b.timestamp));
    let latest_note_hash = match latest_link {
        Some(link) => {
            link.target
                .clone()
                .into_action_hash()
                .ok_or(wasm_error!(WasmErrorInner::Guest(
                    "No action hash associated with link".to_string()
                )))?
        }
        None => original_note_hash.clone(),
    };
    get(latest_note_hash, GetOptions::default())
}

#[hdk_extern]
pub fn get_original_note(original_note_hash: ActionHash) -> ExternResult<Option<Record>> {
    let Some(details) = get_details(original_note_hash, GetOptions::default())? else {
        return Ok(None);
    };
    match details {
        Details::Record(details) => Ok(Some(details.record)),
        _ => Err(wasm_error!(WasmErrorInner::Guest(
            "Malformed get details response".to_string()
        ))),
    }
}

#[hdk_extern]
pub fn get_all_revisions_for_note(original_note_hash: ActionHash) -> ExternResult<Vec<Record>> {
    let Some(Details::Record(record_details)) =
        get_details(original_note_hash.clone(), GetOptions::default())?
    else {
        return Ok(vec![]);
    };
    let get_input: Vec<GetInput> = record_details
        .updates
        .into_iter()
        .map(|update| {
            Ok(GetInput::new(
                update.hashed.hash.into(),
                GetOptions::default(),
            ))
        })
        .collect::<ExternResult<Vec<GetInput>>>()?;
    let records = HDK.with(|hdk| hdk.borrow().get(get_input))?;
    let mut records: Vec<Record> = records.into_iter().flatten().collect();
    records.insert(0, record_details.record);
    Ok(records)
}

#[derive(Serialize, Deserialize, Debug)]
pub struct UpdateNoteInput {
    pub original_note_hash: ActionHash,
    pub updated_note: Note,
}

#[hdk_extern]
pub fn update_note(input: UpdateNoteInput) -> ExternResult<Record> {
    let updated_note_hash = update_entry(input.original_note_hash.clone(), &input.updated_note)?;
    let record = get(updated_note_hash.clone(), GetOptions::default())?.ok_or(wasm_error!(
        WasmErrorInner::Guest("Could not find the newly updated Note".to_string())
    ))?;
    Ok(record)
}

#[hdk_extern]
pub fn delete_note(original_note_hash: ActionHash) -> ExternResult<ActionHash> {
    let path = Path::from("all_notes");
    let links = get_links(
        GetLinksInputBuilder::try_new(path.path_entry_hash()?, LinkTypes::AllNotes)?.build(),
    )?;
    for link in links {
        if let Some(hash) = link.target.into_action_hash() {
            if hash == original_note_hash {
                delete_link(link.create_link_hash)?;
            }
        }
    }
    delete_entry(original_note_hash)
}

#[hdk_extern]
pub fn get_all_deletes_for_note(
    original_note_hash: ActionHash,
) -> ExternResult<Option<Vec<SignedActionHashed>>> {
    let Some(details) = get_details(original_note_hash, GetOptions::default())? else {
        return Ok(None);
    };
    match details {
        Details::Entry(_) => Err(wasm_error!(WasmErrorInner::Guest(
            "Malformed details".into()
        ))),
        Details::Record(record_details) => Ok(Some(record_details.deletes)),
    }
}

#[hdk_extern]
pub fn get_oldest_delete_for_note(
    original_note_hash: ActionHash,
) -> ExternResult<Option<SignedActionHashed>> {
    let Some(mut deletes) = get_all_deletes_for_note(original_note_hash)? else {
        return Ok(None);
    };
    deletes.sort_by(|delete_a, delete_b| {
        delete_a
            .action()
            .timestamp()
            .cmp(&delete_b.action().timestamp())
    });
    Ok(deletes.first().cloned())
}