profile.rs (3489B)
1 use std::collections::HashMap; 2 3 use enostr::{FullKeypair, Pubkey, RelayPool}; 4 use nostrdb::{Ndb, Note, NoteBuildOptions, NoteBuilder, ProfileRecord}; 5 6 use tracing::info; 7 8 use crate::{ 9 profile_state::ProfileState, 10 route::{Route, Router}, 11 }; 12 13 pub struct NostrName<'a> { 14 pub username: Option<&'a str>, 15 pub display_name: Option<&'a str>, 16 pub nip05: Option<&'a str>, 17 } 18 19 impl<'a> NostrName<'a> { 20 pub fn name(&self) -> &'a str { 21 if let Some(name) = self.username { 22 name 23 } else if let Some(name) = self.display_name { 24 name 25 } else { 26 self.nip05.unwrap_or("??") 27 } 28 } 29 30 pub fn unknown() -> Self { 31 Self { 32 username: None, 33 display_name: None, 34 nip05: None, 35 } 36 } 37 } 38 39 fn is_empty(s: &str) -> bool { 40 s.chars().all(|c| c.is_whitespace()) 41 } 42 43 pub fn get_display_name<'a>(record: Option<&ProfileRecord<'a>>) -> NostrName<'a> { 44 if let Some(record) = record { 45 if let Some(profile) = record.record().profile() { 46 let display_name = profile.display_name().filter(|n| !is_empty(n)); 47 let username = profile.name().filter(|n| !is_empty(n)); 48 let nip05 = if let Some(raw_nip05) = profile.nip05() { 49 if let Some(at_pos) = raw_nip05.find('@') { 50 if raw_nip05.starts_with('_') { 51 raw_nip05.get(at_pos + 1..) 52 } else { 53 Some(raw_nip05) 54 } 55 } else { 56 None 57 } 58 } else { 59 None 60 }; 61 62 NostrName { 63 username, 64 display_name, 65 nip05, 66 } 67 } else { 68 NostrName::unknown() 69 } 70 } else { 71 NostrName::unknown() 72 } 73 } 74 75 pub struct SaveProfileChanges { 76 pub kp: FullKeypair, 77 pub state: ProfileState, 78 } 79 80 impl SaveProfileChanges { 81 pub fn new(kp: FullKeypair, state: ProfileState) -> Self { 82 Self { kp, state } 83 } 84 pub fn to_note(&self) -> Note { 85 let sec = &self.kp.secret_key.to_secret_bytes(); 86 add_client_tag(NoteBuilder::new()) 87 .kind(0) 88 .content(&self.state.to_json()) 89 .options(NoteBuildOptions::default().created_at(true).sign(sec)) 90 .build() 91 .expect("should build") 92 } 93 } 94 95 fn add_client_tag(builder: NoteBuilder<'_>) -> NoteBuilder<'_> { 96 builder 97 .start_tag() 98 .tag_str("client") 99 .tag_str("Damus Notedeck") 100 } 101 102 pub enum ProfileAction { 103 Edit(FullKeypair), 104 SaveChanges(SaveProfileChanges), 105 } 106 107 impl ProfileAction { 108 pub fn process( 109 &self, 110 state_map: &mut HashMap<Pubkey, ProfileState>, 111 ndb: &Ndb, 112 pool: &mut RelayPool, 113 router: &mut Router<Route>, 114 ) { 115 match self { 116 ProfileAction::Edit(kp) => { 117 router.route_to(Route::EditProfile(kp.pubkey)); 118 } 119 ProfileAction::SaveChanges(changes) => { 120 let raw_msg = format!("[\"EVENT\",{}]", changes.to_note().json().unwrap()); 121 122 let _ = ndb.process_client_event(raw_msg.as_str()); 123 let _ = state_map.remove_entry(&changes.kp.pubkey); 124 125 info!("sending {}", raw_msg); 126 pool.send(&enostr::ClientMessage::raw(raw_msg)); 127 128 router.go_back(); 129 } 130 } 131 } 132 }