1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-22 21:39:21 +00:00

Build first notifications

This commit is contained in:
Pierre HUBERT 2021-04-15 11:08:11 +02:00
parent b28d102e24
commit 28c0494fe9
7 changed files with 166 additions and 5 deletions

View File

@ -35,7 +35,7 @@ independent-push-service:
control-token: BADTOKENTOCHANGE control-token: BADTOKENTOCHANGE
# Public access URL pattern (for clients access) {TOKEN_URL} will be replaced by client token # Public access URL pattern (for clients access) {TOKEN_URL} will be replaced by client token
public-url: ws://localhost:4500/ws/{TOKEN_URL} public-url: ws://192.168.1.9:4500/ws/{TOKEN_URL}
# Database configuration # Database configuration

View File

@ -39,3 +39,4 @@ pub mod user_ws_message;
pub mod user_ws_connection; pub mod user_ws_connection;
pub mod call_signal; pub mod call_signal;
pub mod new_notifications_settings; pub mod new_notifications_settings;
pub mod push_notification;

View File

@ -0,0 +1,14 @@
//! # Push notification
//!
//! Notification pushed to registered devices
//!
//! @author Pierre Hubert
#[derive(Debug)]
pub struct PushNotification {
pub id: String,
pub title: String,
pub body: String,
pub image: Option<String>,
pub timeout: Option<u64>,
}

View File

@ -36,6 +36,11 @@ impl UserID {
false => None, false => None,
} }
} }
/// Create an owned instance of this user ID object
pub fn as_owned(&self) -> Self {
Self(self.0)
}
} }
impl Hash for UserID { impl Hash for UserID {
@ -136,6 +141,10 @@ pub struct User {
} }
impl User { impl User {
pub fn full_name(&self) -> String {
format!("{} {}", self.first_name, self.last_name)
}
/// Check if user's page is public /// Check if user's page is public
pub fn is_page_public(&self) -> bool { pub fn is_page_public(&self) -> bool {
!matches!(self.status, UserPageStatus::PRIVATE) !matches!(self.status, UserPageStatus::PRIVATE)

View File

@ -461,6 +461,9 @@ pub fn mark_user_seen(conv_id: ConvID, user_id: &UserID, last_msg: &Conversation
.set_u64("last_access", last_msg.time_sent) .set_u64("last_access", last_msg.time_sent)
.exec()?; .exec()?;
// Push an event
events_helper::propagate_event(&Event::SeenLastConversationMessage(user_id, conv_id))?;
// Push an event (updated_number_unread_conversations) // Push an event (updated_number_unread_conversations)
events_helper::propagate_event(&Event::UpdatedNumberUnreadConversations(&vec![user_id.clone()]))?; events_helper::propagate_event(&Event::UpdatedNumberUnreadConversations(&vec![user_id.clone()]))?;

View File

@ -13,6 +13,7 @@ use crate::data::error::Res;
use crate::data::user::UserID; use crate::data::user::UserID;
use crate::data::user_token::UserAccessToken; use crate::data::user_token::UserAccessToken;
use crate::data::user_ws_connection::UserWsConnection; use crate::data::user_ws_connection::UserWsConnection;
use crate::helpers::push_notifications_helper;
pub enum Event<'a> { pub enum Event<'a> {
/// Websocket of a user was closed /// Websocket of a user was closed
@ -26,6 +27,9 @@ pub enum Event<'a> {
/// Updated the number of notifications of one of multiple users user /// Updated the number of notifications of one of multiple users user
UpdatedNotificationsNumber(&'a Vec<UserID>), UpdatedNotificationsNumber(&'a Vec<UserID>),
/// Indicate that a user has seen the last message of a conversation
SeenLastConversationMessage(&'a UserID, ConvID),
/// Updated the number of unread conversations /// Updated the number of unread conversations
UpdatedNumberUnreadConversations(&'a Vec<UserID>), UpdatedNumberUnreadConversations(&'a Vec<UserID>),
@ -89,5 +93,6 @@ pub fn propagate_event(e: &Event) -> Res {
user_ws_controller::handle_event(e)?; user_ws_controller::handle_event(e)?;
calls_controller::handle_event(e)?; calls_controller::handle_event(e)?;
rtc_relay_controller::handle_event(e)?; rtc_relay_controller::handle_event(e)?;
push_notifications_helper::handle_event(e)?;
Ok(()) Ok(())
} }

View File

@ -2,9 +2,15 @@
//! //!
//! @author Pierre Hubert //! @author Pierre Hubert
use crate::data::user_token::{UserAccessToken, PushNotificationToken}; 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::error::Res;
use crate::helpers::independent_push_notifications_service_helper; 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, independent_push_notifications_service_helper, user_helper};
use crate::helpers::events_helper::Event;
/// Un-register for previous push notifications service /// Un-register for previous push notifications service
pub fn un_register_from_previous_service(client: &UserAccessToken) -> Res { pub fn un_register_from_previous_service(client: &UserAccessToken) -> Res {
@ -18,3 +24,126 @@ pub fn un_register_from_previous_service(client: &UserAccessToken) -> Res {
Ok(()) Ok(())
} }
/// Push a notification to specific tokens
fn push_notification(n: &PushNotification, targets: Vec<PushNotificationToken>) -> Res {
// TODO : implement
println!("* Push notification: {:#?} \n* To {:?}", n, targets);
Ok(())
}
/// Cancel a notification for specific tokens (optional)
fn cancel_notification(id: String, targets: Vec<PushNotificationToken>) -> Res {
// TODO : implement
println!("* Cancel push notification: {:#?} \n* For {:?}", id, targets);
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_notifications_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.push_notifications_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 = 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();
push_notification_to_users(&notif, 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(())
}