mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-19 19:46:50 +00:00
Merge pull request #155 from fiatjaf/tag-stuff
Allow mentions/quotes to be made
This commit is contained in:
commit
08c47a4060
@ -6,7 +6,9 @@ use crate::db::{DbEvent, DbEventSeen, DbPersonRelay, DbRelay};
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::globals::GLOBALS;
|
use crate::globals::GLOBALS;
|
||||||
use crate::people::People;
|
use crate::people::People;
|
||||||
use crate::tags::{add_pubkey_to_tags, add_tag, keys_from_text};
|
use crate::tags::{
|
||||||
|
add_event_to_tags, add_pubkey_hex_to_tags, add_pubkey_to_tags, keys_from_text, notes_from_text,
|
||||||
|
};
|
||||||
use minion::Minion;
|
use minion::Minion;
|
||||||
use nostr_types::{
|
use nostr_types::{
|
||||||
Event, EventKind, Id, IdHex, PreEvent, PrivateKey, PublicKey, PublicKeyHex, Tag, Unixtime, Url,
|
Event, EventKind, Id, IdHex, PreEvent, PrivateKey, PublicKey, PublicKeyHex, Tag, Unixtime, Url,
|
||||||
@ -626,7 +628,13 @@ impl Overlord {
|
|||||||
|
|
||||||
// Add tags for keys that are in the post body as npub1...
|
// Add tags for keys that are in the post body as npub1...
|
||||||
for (npub, pubkey) in keys_from_text(&content) {
|
for (npub, pubkey) in keys_from_text(&content) {
|
||||||
let idx = add_pubkey_to_tags(&mut tags, pubkey);
|
let idx = add_pubkey_to_tags(&mut tags, pubkey).await;
|
||||||
|
content = content.replace(&npub, &format!("#[{}]", idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same as above, but now with note1...
|
||||||
|
for (npub, pubkey) in notes_from_text(&content) {
|
||||||
|
let idx = add_event_to_tags(&mut tags, pubkey, "mention").await;
|
||||||
content = content.replace(&npub, &format!("#[{}]", idx));
|
content = content.replace(&npub, &format!("#[{}]", idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,46 +715,43 @@ impl Overlord {
|
|||||||
// Add a 'p' tag for the author we are replying to (except if it is our own key)
|
// Add a 'p' tag for the author we are replying to (except if it is our own key)
|
||||||
if let Some(pubkey) = GLOBALS.signer.read().await.public_key() {
|
if let Some(pubkey) = GLOBALS.signer.read().await.public_key() {
|
||||||
if pubkey != event.pubkey {
|
if pubkey != event.pubkey {
|
||||||
add_pubkey_to_tags(&mut tags, pubkey);
|
add_pubkey_to_tags(&mut tags, pubkey).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all the 'p' tags from the note we are replying to (except our own)
|
// Add all the 'p' tags from the note we are replying to (except our own)
|
||||||
for tag in &event.tags {
|
for tag in &event.tags {
|
||||||
if tag.tagname() == "p" {
|
match tag {
|
||||||
add_tag(&mut tags, tag);
|
Tag::Pubkey { pubkey, .. } => {
|
||||||
|
add_pubkey_hex_to_tags(&mut tags, pubkey).await;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add tags for keys that are in the post body as npub1...
|
// Add tags for keys that are in the post body as npub1...
|
||||||
for (npub, pubkey) in keys_from_text(&content) {
|
for (npub, pubkey) in keys_from_text(&content) {
|
||||||
let idx = add_pubkey_to_tags(&mut tags, pubkey);
|
let idx = add_pubkey_to_tags(&mut tags, pubkey).await;
|
||||||
|
content = content.replace(&npub, &format!("#[{}]", idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do the same as above, but now with note1...
|
||||||
|
for (npub, pubkey) in notes_from_text(&content) {
|
||||||
|
// NIP-10: "Those marked with "mention" denote a quoted or reposted event id."
|
||||||
|
let idx = add_event_to_tags(&mut tags, pubkey, "mention").await;
|
||||||
content = content.replace(&npub, &format!("#[{}]", idx));
|
content = content.replace(&npub, &format!("#[{}]", idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((root, _maybeurl)) = event.replies_to_root() {
|
if let Some((root, _maybeurl)) = event.replies_to_root() {
|
||||||
// Add an 'e' tag for the root
|
// Add an 'e' tag for the root
|
||||||
tags.push(Tag::Event {
|
add_event_to_tags(&mut tags, root, "root").await;
|
||||||
id: root,
|
|
||||||
recommended_relay_url: DbRelay::recommended_relay_for_reply(root).await?,
|
|
||||||
marker: Some("root".to_string()),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add an 'e' tag for the note we are replying to
|
// Add an 'e' tag for the note we are replying to
|
||||||
tags.push(Tag::Event {
|
add_event_to_tags(&mut tags, reply_to, "reply").await;
|
||||||
id: reply_to,
|
|
||||||
recommended_relay_url: DbRelay::recommended_relay_for_reply(reply_to).await?,
|
|
||||||
marker: Some("reply".to_string()),
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// We are replying to the root.
|
// We are replying to the root.
|
||||||
// NIP-10: "A direct reply to the root of a thread should have a single marked "e" tag of type "root"."
|
// NIP-10: "A direct reply to the root of a thread should have a single marked "e" tag of type "root"."
|
||||||
|
add_event_to_tags(&mut tags, reply_to, "root").await;
|
||||||
tags.push(Tag::Event {
|
|
||||||
id: reply_to,
|
|
||||||
recommended_relay_url: DbRelay::recommended_relay_for_reply(reply_to).await?,
|
|
||||||
marker: Some("root".to_string()),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if GLOBALS.settings.read().await.set_client_tag {
|
if GLOBALS.settings.read().await.set_client_tag {
|
||||||
|
149
src/tags.rs
149
src/tags.rs
@ -1,8 +1,9 @@
|
|||||||
use nostr_types::{PublicKey, Tag};
|
use crate::db::DbRelay;
|
||||||
|
use nostr_types::{Id, PublicKey, PublicKeyHex, Tag};
|
||||||
|
|
||||||
pub fn keys_from_text(text: &str) -> Vec<(String, PublicKey)> {
|
pub fn keys_from_text(text: &str) -> Vec<(String, PublicKey)> {
|
||||||
let mut pubkeys: Vec<(String, PublicKey)> = text
|
let mut pubkeys: Vec<(String, PublicKey)> = text
|
||||||
.split(&[' ', ',', '.', ':', ';', '?', '!', '/'][..])
|
.split(|c: char| !c.is_alphanumeric())
|
||||||
.filter_map(|npub| {
|
.filter_map(|npub| {
|
||||||
if !npub.starts_with("npub1") {
|
if !npub.starts_with("npub1") {
|
||||||
None
|
None
|
||||||
@ -18,67 +19,95 @@ pub fn keys_from_text(text: &str) -> Vec<(String, PublicKey)> {
|
|||||||
pubkeys
|
pubkeys
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_pubkey_to_tags(existing_tags: &mut Vec<Tag>, added: PublicKey) -> usize {
|
pub fn notes_from_text(text: &str) -> Vec<(String, Id)> {
|
||||||
add_tag(
|
let mut noteids: Vec<(String, Id)> = text
|
||||||
existing_tags,
|
.split(|c: char| !c.is_alphanumeric())
|
||||||
&Tag::Pubkey {
|
.filter_map(|note| {
|
||||||
pubkey: added.as_hex_string().into(),
|
if !note.starts_with("note1") {
|
||||||
recommended_relay_url: None,
|
None
|
||||||
petname: None,
|
} else {
|
||||||
},
|
Id::try_from_bech32_string(¬e)
|
||||||
)
|
.ok()
|
||||||
|
.map(|id| (note.to_string(), id))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
noteids.sort_unstable_by_key(|ni| ni.1);
|
||||||
|
noteids.dedup();
|
||||||
|
noteids
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_tag(existing_tags: &mut Vec<Tag>, added: &Tag) -> usize {
|
pub async fn add_pubkey_hex_to_tags(existing_tags: &mut Vec<Tag>, hex: &PublicKeyHex) -> usize {
|
||||||
match added {
|
let newtag = Tag::Pubkey {
|
||||||
Tag::Pubkey { pubkey, .. } => {
|
pubkey: hex.to_owned(),
|
||||||
match existing_tags.iter().position(|existing_tag| {
|
recommended_relay_url: None,
|
||||||
matches!(
|
petname: None,
|
||||||
existing_tag,
|
};
|
||||||
Tag::Pubkey { pubkey: existing_p, .. } if existing_p.0 == pubkey.0
|
|
||||||
)
|
match existing_tags.iter().position(|existing_tag| {
|
||||||
}) {
|
matches!(
|
||||||
None => {
|
existing_tag,
|
||||||
// add (FIXME: include relay hint it not exists)
|
Tag::Pubkey { pubkey: existing_p, .. } if existing_p.0 == hex.0
|
||||||
existing_tags.push(added.to_owned());
|
)
|
||||||
existing_tags.len() - 1
|
}) {
|
||||||
}
|
None => {
|
||||||
Some(idx) => idx,
|
// FIXME: include relay hint
|
||||||
}
|
existing_tags.push(newtag);
|
||||||
}
|
|
||||||
Tag::Event { id, .. } => {
|
|
||||||
match existing_tags.iter().position(|existing_tag| {
|
|
||||||
matches!(
|
|
||||||
existing_tag,
|
|
||||||
Tag::Event { id: existing_e, .. } if existing_e.0 == id.0
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
None => {
|
|
||||||
// add (FIXME: include relay hint it not exists)
|
|
||||||
existing_tags.push(added.to_owned());
|
|
||||||
existing_tags.len() - 1
|
|
||||||
}
|
|
||||||
Some(idx) => idx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tag::Hashtag(hashtag) => {
|
|
||||||
match existing_tags.iter().position(|existing_tag| {
|
|
||||||
matches!(
|
|
||||||
existing_tag,
|
|
||||||
Tag::Hashtag(existing_hashtag) if existing_hashtag == hashtag
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
None => {
|
|
||||||
// add (FIXME: include relay hint it not exists)
|
|
||||||
existing_tags.push(added.to_owned());
|
|
||||||
existing_tags.len() - 1
|
|
||||||
}
|
|
||||||
Some(idx) => idx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
existing_tags.push(added.to_owned());
|
|
||||||
existing_tags.len() - 1
|
existing_tags.len() - 1
|
||||||
}
|
}
|
||||||
|
Some(idx) => idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_pubkey_to_tags(existing_tags: &mut Vec<Tag>, added: PublicKey) -> usize {
|
||||||
|
add_pubkey_hex_to_tags(existing_tags, &added.as_hex_string().into()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_event_to_tags(existing_tags: &mut Vec<Tag>, added: Id, marker: &str) -> usize {
|
||||||
|
let newtag = Tag::Event {
|
||||||
|
id: added,
|
||||||
|
recommended_relay_url: DbRelay::recommended_relay_for_reply(added)
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.flatten(),
|
||||||
|
marker: Some(marker.to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match existing_tags.iter().position(|existing_tag| {
|
||||||
|
matches!(
|
||||||
|
existing_tag,
|
||||||
|
Tag::Event { id: existing_e, .. } if existing_e.0 == added.0
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
None => {
|
||||||
|
existing_tags.push(newtag);
|
||||||
|
existing_tags.len() - 1
|
||||||
|
}
|
||||||
|
Some(idx) => idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_pubkeys() {
|
||||||
|
let pubkeys = keys_from_text("hello npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6 and npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6... actually npub1melv683fw6n2mvhl5h6dhqd8mqfv3wmxnz4qph83ua4dk4006ezsrt5c24");
|
||||||
|
assert_eq!(pubkeys.len(), 2);
|
||||||
|
assert_eq!(
|
||||||
|
pubkeys[0].1.as_hex_string(),
|
||||||
|
"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_notes() {
|
||||||
|
let ids = notes_from_text(
|
||||||
|
"note1pm88wxjcqfh886gf5tvzjwe6k0crmxzdwtfnmn7ww93dh8dcrkhq82j67f
|
||||||
|
|
||||||
|
Another naïve person falling for the scam of deletes.",
|
||||||
|
);
|
||||||
|
assert_eq!(ids.len(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ fn real_posting_area(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
|
|||||||
ui.menu_button("@", |ui| {
|
ui.menu_button("@", |ui| {
|
||||||
for pair in pairs {
|
for pair in pairs {
|
||||||
if ui.button(pair.0).clicked() {
|
if ui.button(pair.0).clicked() {
|
||||||
if !app.draft.ends_with(' ') {
|
if !app.draft.ends_with(' ') && app.draft != "" {
|
||||||
app.draft.push(' ');
|
app.draft.push(' ');
|
||||||
}
|
}
|
||||||
app.draft.push_str(&pair.1.try_as_bech32_string().unwrap());
|
app.draft.push_str(&pair.1.try_as_bech32_string().unwrap());
|
||||||
@ -513,6 +513,21 @@ fn render_post_actual(
|
|||||||
|
|
||||||
ui.add_space(24.0);
|
ui.add_space(24.0);
|
||||||
|
|
||||||
|
// Button to quote note
|
||||||
|
if ui
|
||||||
|
.add(Label::new(RichText::new("»").size(18.0)).sense(Sense::click()))
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
if !app.draft.ends_with(" ") && app.draft != "" {
|
||||||
|
app.draft.push_str(" ");
|
||||||
|
}
|
||||||
|
app.draft
|
||||||
|
.push_str(&event.id.try_as_bech32_string().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add_space(24.0);
|
||||||
|
|
||||||
|
// Button to reply
|
||||||
if ui
|
if ui
|
||||||
.add(Label::new(RichText::new("💬").size(18.0)).sense(Sense::click()))
|
.add(Label::new(RichText::new("💬").size(18.0)).sense(Sense::click()))
|
||||||
.clicked()
|
.clicked()
|
||||||
@ -522,6 +537,7 @@ fn render_post_actual(
|
|||||||
|
|
||||||
ui.add_space(24.0);
|
ui.add_space(24.0);
|
||||||
|
|
||||||
|
// Buttons to react and reaction counts
|
||||||
if app.settings.reactions {
|
if app.settings.reactions {
|
||||||
if ui
|
if ui
|
||||||
.add(
|
.add(
|
||||||
|
Loading…
Reference in New Issue
Block a user