mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-10-31 07:34:45 +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(())
 | |
| } |