mirror of
https://github.com/nostrlabs-io/notepush.git
synced 2025-06-16 11:48:51 +00:00
Add support to "only notifications from following" setting
Testing ------- PASS Devices: Mix of iPhone simulators and real devices notepush: This commit Damus: 4ea6c360e6e33747cb09ecf085049948ec1dadd1 (WIP change from GH issue #2360) Setup: - Account A with push notifications enabled, DM notifications enabled, and "only notifications from following enabled" - Account A follows B but not C Steps: 1. Send DM to A from B. Push notification appears 2. Send DM to A from C. Push notification does not appear Signed-off-by: Daniel D’Aquino <daniel@daquino.me> Closes: https://github.com/damus-io/damus/issues/2360
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
pub mod mute_manager;
|
pub mod nostr_network_helper;
|
||||||
mod nostr_event_extensions;
|
mod nostr_event_extensions;
|
||||||
pub mod notification_manager;
|
pub mod notification_manager;
|
||||||
|
|
||||||
pub use mute_manager::MuteManager;
|
pub use nostr_network_helper::NostrNetworkHelper;
|
||||||
use nostr_event_extensions::{ExtendedEvent, SqlStringConvertible};
|
use nostr_event_extensions::{ExtendedEvent, SqlStringConvertible};
|
||||||
pub use notification_manager::NotificationManager;
|
pub use notification_manager::NotificationManager;
|
||||||
|
@ -2,16 +2,16 @@ use super::ExtendedEvent;
|
|||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
use tokio::time::{timeout, Duration};
|
use tokio::time::{timeout, Duration};
|
||||||
|
|
||||||
pub struct MuteManager {
|
pub struct NostrNetworkHelper {
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MuteManager {
|
impl NostrNetworkHelper {
|
||||||
pub async fn new(relay_url: String) -> Result<Self, Box<dyn std::error::Error>> {
|
pub async fn new(relay_url: String) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let client = Client::new(&Keys::generate());
|
let client = Client::new(&Keys::generate());
|
||||||
client.add_relay(relay_url.clone()).await?;
|
client.add_relay(relay_url.clone()).await?;
|
||||||
client.connect().await;
|
client.connect().await;
|
||||||
Ok(MuteManager { client })
|
Ok(NostrNetworkHelper { client })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn should_mute_notification_for_pubkey(
|
pub async fn should_mute_notification_for_pubkey(
|
||||||
@ -125,4 +125,63 @@ impl MuteManager {
|
|||||||
self.client.unsubscribe(this_subscription_id).await;
|
self.client.unsubscribe(this_subscription_id).await;
|
||||||
mute_list
|
mute_list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn does_pubkey_follow_pubkey(
|
||||||
|
&self,
|
||||||
|
source_pubkey: &PublicKey,
|
||||||
|
target_pubkey: &PublicKey,
|
||||||
|
) -> bool {
|
||||||
|
log::debug!(
|
||||||
|
"Checking if pubkey {:?} follows pubkey {:?}",
|
||||||
|
source_pubkey,
|
||||||
|
target_pubkey
|
||||||
|
);
|
||||||
|
if let Some(contact_list) = self.get_contact_list(source_pubkey).await {
|
||||||
|
let tag_contents = contact_list.get_tags_content(TagKind::SingleLetter(SingleLetterTag {
|
||||||
|
character: Alphabet::P,
|
||||||
|
uppercase: false,
|
||||||
|
}));
|
||||||
|
return tag_contents.iter().any(|t| t == &target_pubkey.to_hex());
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_contact_list(&self, pubkey: &PublicKey) -> Option<Event> {
|
||||||
|
let subscription_filter = Filter::new()
|
||||||
|
.kinds(vec![Kind::ContactList])
|
||||||
|
.authors(vec![pubkey.clone()])
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
let this_subscription_id = self
|
||||||
|
.client
|
||||||
|
.subscribe(Vec::from([subscription_filter]), None)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let mut contact_list: Option<Event> = None;
|
||||||
|
let mut notifications = self.client.notifications();
|
||||||
|
|
||||||
|
let timeout_duration = Duration::from_secs(10);
|
||||||
|
while let Ok(result) = timeout(timeout_duration, notifications.recv()).await {
|
||||||
|
if let Ok(notification) = result {
|
||||||
|
if let RelayPoolNotification::Event {
|
||||||
|
subscription_id,
|
||||||
|
event,
|
||||||
|
..
|
||||||
|
} = notification
|
||||||
|
{
|
||||||
|
if this_subscription_id == subscription_id && event.kind == Kind::ContactList {
|
||||||
|
contact_list = Some((*event).clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if contact_list.is_none() {
|
||||||
|
log::debug!("Contact list not found for pubkey {:?}", pubkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.client.unsubscribe(this_subscription_id).await;
|
||||||
|
contact_list
|
||||||
|
}
|
||||||
}
|
}
|
@ -13,7 +13,7 @@ use tokio::sync::Mutex;
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use tokio;
|
use tokio;
|
||||||
|
|
||||||
use super::mute_manager::MuteManager;
|
use super::nostr_network_helper::NostrNetworkHelper;
|
||||||
use super::ExtendedEvent;
|
use super::ExtendedEvent;
|
||||||
use super::SqlStringConvertible;
|
use super::SqlStringConvertible;
|
||||||
use nostr::Event;
|
use nostr::Event;
|
||||||
@ -28,7 +28,7 @@ pub struct NotificationManager {
|
|||||||
apns_topic: String,
|
apns_topic: String,
|
||||||
apns_client: Mutex<Client>,
|
apns_client: Mutex<Client>,
|
||||||
|
|
||||||
mute_manager: Mutex<MuteManager>,
|
nostr_network_helper: Mutex<NostrNetworkHelper>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NotificationManager {
|
impl NotificationManager {
|
||||||
@ -43,7 +43,7 @@ impl NotificationManager {
|
|||||||
apns_environment: a2::client::Endpoint,
|
apns_environment: a2::client::Endpoint,
|
||||||
apns_topic: String,
|
apns_topic: String,
|
||||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||||
let mute_manager = MuteManager::new(relay_url.clone()).await?;
|
let mute_manager = NostrNetworkHelper::new(relay_url.clone()).await?;
|
||||||
|
|
||||||
let connection = db.get()?;
|
let connection = db.get()?;
|
||||||
Self::setup_database(&connection)?;
|
Self::setup_database(&connection)?;
|
||||||
@ -61,7 +61,7 @@ impl NotificationManager {
|
|||||||
apns_topic,
|
apns_topic,
|
||||||
apns_client: Mutex::new(client),
|
apns_client: Mutex::new(client),
|
||||||
db: Mutex::new(db),
|
db: Mutex::new(db),
|
||||||
mute_manager: Mutex::new(mute_manager),
|
nostr_network_helper: Mutex::new(mute_manager),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ impl NotificationManager {
|
|||||||
let mut pubkeys_to_notify = HashSet::new();
|
let mut pubkeys_to_notify = HashSet::new();
|
||||||
for pubkey in relevant_pubkeys_yet_to_receive {
|
for pubkey in relevant_pubkeys_yet_to_receive {
|
||||||
let should_mute: bool = {
|
let should_mute: bool = {
|
||||||
let mute_manager_mutex_guard = self.mute_manager.lock().await;
|
let mute_manager_mutex_guard = self.nostr_network_helper.lock().await;
|
||||||
mute_manager_mutex_guard
|
mute_manager_mutex_guard
|
||||||
.should_mute_notification_for_pubkey(event, &pubkey)
|
.should_mute_notification_for_pubkey(event, &pubkey)
|
||||||
.await
|
.await
|
||||||
@ -285,6 +285,12 @@ impl NotificationManager {
|
|||||||
event: &Event,
|
event: &Event,
|
||||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||||
let notification_preferences = self.get_user_notification_settings(pubkey, device_token).await?;
|
let notification_preferences = self.get_user_notification_settings(pubkey, device_token).await?;
|
||||||
|
if notification_preferences.only_notifications_from_following_enabled {
|
||||||
|
let nostr_network_helper_mutex_guard = self.nostr_network_helper.lock().await;
|
||||||
|
if !nostr_network_helper_mutex_guard.does_pubkey_follow_pubkey(pubkey, &event.author()).await {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
match event.kind {
|
match event.kind {
|
||||||
Kind::TextNote => Ok(notification_preferences.mention_notifications_enabled), // TODO: Not 100% accurate
|
Kind::TextNote => Ok(notification_preferences.mention_notifications_enabled), // TODO: Not 100% accurate
|
||||||
Kind::EncryptedDirectMessage => Ok(notification_preferences.dm_notifications_enabled),
|
Kind::EncryptedDirectMessage => Ok(notification_preferences.dm_notifications_enabled),
|
||||||
|
Reference in New Issue
Block a user