mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2025-02-18 06:52:39 +00:00
191 lines
5.7 KiB
Rust
191 lines
5.7 KiB
Rust
//! # Push notifications helper
|
|
//!
|
|
//! @author Pierre Hubert
|
|
|
|
use crate::controllers::user_ws_controller;
|
|
use crate::data::conversation::ConvID;
|
|
use crate::data::conversation_message::ConversationMessage;
|
|
use crate::data::error::Res;
|
|
use crate::data::push_notification::PushNotification;
|
|
use crate::data::user::UserID;
|
|
use crate::data::user_token::{PushNotificationToken, UserAccessToken};
|
|
use crate::helpers::{account_helper, conversations_helper, firebase_notifications_helper, independent_push_notifications_service_helper, user_helper};
|
|
use crate::helpers::events_helper::Event;
|
|
|
|
/// Un-register for previous push notifications service
|
|
pub fn un_register_from_previous_service(client: &UserAccessToken) -> Res {
|
|
|
|
// This method must not fail in case of error
|
|
if let PushNotificationToken::INDEPENDENT(old_token) = &client.push_notifications_token {
|
|
if let Err(e) = independent_push_notifications_service_helper::remove_token(old_token) {
|
|
eprintln!("Failed to un-register from independent push notifications service! {}", e);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Split tokens in categories : (Independent, Firebase)
|
|
fn split_tokens(targets: Vec<UserAccessToken>) -> (Vec<String>, Vec<UserAccessToken>) {
|
|
let mut independent = vec![];
|
|
let mut firebase = vec![];
|
|
|
|
for target in targets {
|
|
match target.push_notifications_token {
|
|
PushNotificationToken::INDEPENDENT(token) => {
|
|
independent.push(token)
|
|
}
|
|
|
|
PushNotificationToken::FIREBASE(_) => {
|
|
firebase.push(target);
|
|
}
|
|
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
(independent, firebase)
|
|
}
|
|
|
|
/// Push a notification to specific tokens
|
|
fn push_notification(n: &PushNotification, targets: Vec<UserAccessToken>) -> Res {
|
|
let (independents, firebase) = split_tokens(targets);
|
|
|
|
// Push independent notifications
|
|
if !independents.is_empty() {
|
|
independent_push_notifications_service_helper::push_notifications(n, independents)?;
|
|
}
|
|
|
|
// Push Firebase notifications
|
|
if !firebase.is_empty() {
|
|
firebase_notifications_helper::push_notifications(n, firebase)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Cancel a notification for specific tokens (optional)
|
|
fn cancel_notification(id: String, targets: Vec<UserAccessToken>) -> Res {
|
|
let (independents, _) = split_tokens(targets);
|
|
|
|
if !independents.is_empty() {
|
|
independent_push_notifications_service_helper::cancel_notifications(id, independents)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Push a notification to specific users, only if they are not connected
|
|
fn push_notification_to_users(n: &PushNotification, users: Vec<UserID>) -> Res {
|
|
let dest_users: Vec<UserID> = users.into_iter()
|
|
.filter(|u| !user_ws_controller::is_user_connected(u))
|
|
.collect();
|
|
|
|
let mut dest_tokens = vec![];
|
|
|
|
for user in dest_users {
|
|
for token in account_helper::get_all_login_tokens(&user)? {
|
|
dest_tokens.push(token);
|
|
}
|
|
}
|
|
|
|
push_notification(n, dest_tokens)
|
|
}
|
|
|
|
/// Cancel a notification for one or more users
|
|
fn cancel_notification_for_users(id: String, users: Vec<UserID>) -> Res {
|
|
let mut dest_tokens = vec![];
|
|
|
|
for user in users {
|
|
for token in account_helper::get_all_login_tokens(&user)? {
|
|
dest_tokens.push(token);
|
|
}
|
|
}
|
|
|
|
cancel_notification(id, dest_tokens)
|
|
}
|
|
|
|
/// Create a conversation notification
|
|
pub fn create_conversation_notification(msg: &ConversationMessage) -> Res {
|
|
let user_id = match &msg.user_id {
|
|
Some(id) => id,
|
|
None => {
|
|
// Do no create notifications for server messages
|
|
return Ok(());
|
|
}
|
|
};
|
|
|
|
let user = user_helper::find_user_by_id(user_id)?;
|
|
let conv = conversations_helper::get_single(msg.conv_id)?;
|
|
|
|
let notif_title = match conv.name {
|
|
None => user.full_name(),
|
|
Some(name) => format!("{} ({})", user.full_name(), name)
|
|
};
|
|
|
|
let notif_message = match &msg.message {
|
|
None => "Shared file".to_string(),
|
|
Some(msg) => msg.to_string()
|
|
};
|
|
|
|
let notif = PushNotification {
|
|
id: format!("conv-{}", msg.conv_id.id()),
|
|
title: notif_title,
|
|
body: notif_message,
|
|
image: None,
|
|
timeout: None,
|
|
};
|
|
|
|
let list: Vec<UserID> = conversations_helper::get_list_members(msg.conv_id)?
|
|
.into_iter()
|
|
.filter(|m| m.following && m.user_id != user_id)
|
|
.map(|m| m.user_id)
|
|
.collect();
|
|
|
|
// Select only users who allowed push notifications
|
|
let mut dest_list = vec![];
|
|
for el in list {
|
|
if user_helper::find_user_by_id(&el)?.allow_notif_conv {
|
|
dest_list.push(el);
|
|
}
|
|
}
|
|
|
|
push_notification_to_users(¬if, dest_list)
|
|
}
|
|
|
|
/// Dismiss a conversation notification
|
|
pub fn cancel_conversation_notification(conv_id: ConvID, users: Option<Vec<UserID>>) -> Res {
|
|
let notif_id = format!("conv-{}", conv_id.id());
|
|
|
|
let list = match users {
|
|
Some(users) => users,
|
|
None => conversations_helper::get_list_members(conv_id)?
|
|
.into_iter().map(|m| m.user_id).collect()
|
|
};
|
|
|
|
cancel_notification_for_users(notif_id, list)
|
|
}
|
|
|
|
|
|
/// Handle event. This method NEVER returns Err
|
|
pub fn handle_event(e: &Event) -> Res {
|
|
if let Err(e) = handle_event_internal(e) {
|
|
eprintln!("Failed to create push notifications associated with event! {}", e);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn handle_event_internal(e: &Event) -> Res {
|
|
match e {
|
|
Event::NewConversationMessage(msg) => {
|
|
create_conversation_notification(msg)?;
|
|
}
|
|
Event::SeenLastConversationMessage(user_id, conv_id) => {
|
|
cancel_conversation_notification(*conv_id, Some(vec![user_id.as_owned()]))?;
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
Ok(())
|
|
} |