post.rs (3368B)
1 use enostr::FullKeypair; 2 use nostrdb::{Note, NoteBuilder, NoteReply}; 3 use std::collections::HashSet; 4 5 pub struct NewPost { 6 pub content: String, 7 pub account: FullKeypair, 8 } 9 10 fn add_client_tag(builder: NoteBuilder<'_>) -> NoteBuilder<'_> { 11 builder 12 .start_tag() 13 .tag_str("client") 14 .tag_str("Damus Notedeck") 15 } 16 17 impl NewPost { 18 pub fn new(content: String, account: FullKeypair) -> Self { 19 NewPost { content, account } 20 } 21 22 pub fn to_note(&self, seckey: &[u8; 32]) -> Note { 23 add_client_tag(NoteBuilder::new()) 24 .kind(1) 25 .content(&self.content) 26 .sign(seckey) 27 .build() 28 .expect("note should be ok") 29 } 30 31 pub fn to_reply(&self, seckey: &[u8; 32], replying_to: &Note) -> Note { 32 let builder = add_client_tag(NoteBuilder::new()) 33 .kind(1) 34 .content(&self.content); 35 36 let nip10 = NoteReply::new(replying_to.tags()); 37 38 let mut builder = if let Some(root) = nip10.root() { 39 builder 40 .start_tag() 41 .tag_str("e") 42 .tag_str(&hex::encode(root.id)) 43 .tag_str("") 44 .tag_str("root") 45 .start_tag() 46 .tag_str("e") 47 .tag_str(&hex::encode(replying_to.id())) 48 .tag_str("") 49 .tag_str("reply") 50 .sign(seckey) 51 } else { 52 // we're replying to a post that isn't in a thread, 53 // just add a single reply-to-root tag 54 builder 55 .start_tag() 56 .tag_str("e") 57 .tag_str(&hex::encode(replying_to.id())) 58 .tag_str("") 59 .tag_str("root") 60 .sign(seckey) 61 }; 62 63 let mut seen_p: HashSet<&[u8; 32]> = HashSet::new(); 64 65 builder = builder 66 .start_tag() 67 .tag_str("p") 68 .tag_str(&hex::encode(replying_to.pubkey())); 69 70 seen_p.insert(replying_to.pubkey()); 71 72 for tag in replying_to.tags() { 73 if tag.count() < 2 { 74 continue; 75 } 76 77 if tag.get_unchecked(0).variant().str() != Some("p") { 78 continue; 79 } 80 81 let id = if let Some(id) = tag.get_unchecked(1).variant().id() { 82 id 83 } else { 84 continue; 85 }; 86 87 if seen_p.contains(id) { 88 continue; 89 } 90 91 seen_p.insert(id); 92 93 builder = builder.start_tag().tag_str("p").tag_str(&hex::encode(id)); 94 } 95 96 builder 97 .sign(seckey) 98 .build() 99 .expect("expected build to work") 100 } 101 102 pub fn to_quote(&self, seckey: &[u8; 32], quoting: &Note) -> Note { 103 let new_content = format!( 104 "{}\nnostr:{}", 105 self.content, 106 enostr::NoteId::new(*quoting.id()).to_bech().unwrap() 107 ); 108 109 NoteBuilder::new() 110 .kind(1) 111 .content(&new_content) 112 .start_tag() 113 .tag_str("q") 114 .tag_str(&hex::encode(quoting.id())) 115 .start_tag() 116 .tag_str("p") 117 .tag_str(&hex::encode(quoting.pubkey())) 118 .sign(seckey) 119 .build() 120 .expect("expected build to work") 121 } 122 }