nostr_database/
profile.rs

1// Copyright (c) 2022-2023 Yuki Kishimoto
2// Copyright (c) 2023-2025 Rust Nostr Developers
3// Distributed under the MIT software license
4
5//! Profile
6
7use core::cmp::Ordering;
8use core::hash::{Hash, Hasher};
9
10use nostr::{Metadata, PublicKey};
11
12/// Profile
13#[derive(Debug, Clone)]
14pub struct Profile {
15    public_key: PublicKey,
16    metadata: Metadata,
17}
18
19impl PartialEq for Profile {
20    fn eq(&self, other: &Self) -> bool {
21        self.public_key == other.public_key
22    }
23}
24
25impl Eq for Profile {}
26
27impl PartialOrd for Profile {
28    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
29        Some(self.cmp(other))
30    }
31}
32
33impl Ord for Profile {
34    fn cmp(&self, other: &Self) -> Ordering {
35        self.name().cmp(&other.name())
36    }
37}
38
39impl Hash for Profile {
40    fn hash<H: Hasher>(&self, state: &mut H) {
41        self.public_key.hash(state)
42    }
43}
44
45impl From<PublicKey> for Profile {
46    fn from(public_key: PublicKey) -> Self {
47        Self::new(public_key, Metadata::default())
48    }
49}
50
51impl Profile {
52    /// Compose new profile
53    pub fn new(public_key: PublicKey, metadata: Metadata) -> Self {
54        Self {
55            public_key,
56            metadata,
57        }
58    }
59
60    /// Get profile public key
61    pub fn public_key(&self) -> PublicKey {
62        self.public_key
63    }
64
65    /// Get profile metadata
66    pub fn metadata(&self) -> Metadata {
67        self.metadata.clone()
68    }
69
70    /// Get profile name
71    ///
72    /// Steps (go to next step if field is `None` or `empty`):
73    /// * Check `display_name` field
74    /// * Check `name` field
75    /// * Return cutted public key (ex. `00000000:00000002`)
76    pub fn name(&self) -> String {
77        if let Some(display_name) = &self.metadata.display_name {
78            if !display_name.is_empty() {
79                return display_name.clone();
80            }
81        }
82
83        if let Some(name) = &self.metadata.name {
84            if !name.is_empty() {
85                return name.clone();
86            }
87        }
88
89        cut_public_key(self.public_key)
90    }
91}
92
93/// Get the first and last 8 chars of a [`PublicKey`]
94///
95/// Ex. `00000000:00000002`
96pub fn cut_public_key(pk: PublicKey) -> String {
97    let pk = pk.to_string();
98    format!("{}:{}", &pk[0..8], &pk[pk.len() - 8..])
99}