Skip to content

Commit

Permalink
Implement notifications for message tips (#4427)
Browse files Browse the repository at this point in the history
  • Loading branch information
hpeebles authored Sep 22, 2023
1 parent 079ee0c commit 8db9d2c
Show file tree
Hide file tree
Showing 19 changed files with 279 additions and 62 deletions.
5 changes: 5 additions & 0 deletions backend/canisters/community/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [unreleased]

### Added

- Implement tipping messages ([#4420](https://github.com/open-chat-labs/open-chat/pull/4420))
- Implement notifications for message tips ([#4427](https://github.com/open-chat-labs/open-chat/pull/4427))

### Changed

- Disable mentions for messages sent by the ProposalsBot ([#4424](https://github.com/open-chat-labs/open-chat/pull/4424))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@ use types::{ChannelId, CompletedCryptoTransaction, MessageId, MessageIndex, User

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub struct Args {
pub message_sender: UserId,
pub recipient: UserId,
pub channel_id: ChannelId,
pub thread_root_message_index: Option<MessageIndex>,
pub message_id: MessageId,
pub transfer: CompletedCryptoTransaction,
pub username: String,
pub display_name: Option<String>,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub enum Response {
Success,
MessageNotFound,
CannotTipSelf,
MessageSenderMismatch,
RecipientMismatch,
NotAuthorized,
CommunityFrozen,
UserNotInCommunity,
Expand Down
37 changes: 34 additions & 3 deletions backend/canisters/community/impl/src/updates/c2c_tip_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use crate::activity_notifications::handle_activity_notification;
use crate::{mutate_state, run_regular_jobs, RuntimeState};
use canister_api_macros::update_msgpack;
use canister_tracing_macros::trace;
use chat_events::Reader;
use community_canister::c2c_tip_message::{Response::*, *};
use group_chat_core::TipMessageResult;
use ledger_utils::format_crypto_amount_with_symbol;
use types::{ChannelMessageTipped, EventIndex, Notification};

#[update_msgpack]
#[trace]
Expand All @@ -26,22 +29,50 @@ fn c2c_tip_message_impl(args: Args, state: &mut RuntimeState) -> Response {

if let Some(channel) = state.data.channels.get_mut(&args.channel_id) {
let now = state.env.now();
let token = args.transfer.token();
let amount = args.transfer.units();

match channel.chat.tip_message(
user_id,
args.message_sender,
args.recipient,
args.thread_root_message_index,
args.message_id,
args.transfer,
now,
) {
TipMessageResult::Success => {
// TODO push notification
if let Some((message_index, message_event_index)) = channel
.chat
.events
.events_reader(EventIndex::default(), args.thread_root_message_index, now)
.and_then(|r| {
r.message_event_internal(args.message_id.into())
.map(|e| (e.event.message_index, e.index))
})
{
let notification = Notification::ChannelMessageTipped(ChannelMessageTipped {
community_id: state.env.canister_id().into(),
channel_id: channel.id,
thread_root_message_index: args.thread_root_message_index,
message_index,
message_event_index,
community_name: state.data.name.clone(),
channel_name: channel.chat.name.clone(),
tipped_by: user_id,
tipped_by_name: args.username,
tipped_by_display_name: args.display_name,
tip: format_crypto_amount_with_symbol(amount, token.decimals().unwrap_or(8), token.token_symbol()),
community_avatar_id: state.data.avatar.as_ref().map(|a| a.id),
channel_avatar_id: channel.chat.avatar.as_ref().map(|a| a.id),
});
state.push_notification(vec![args.recipient], notification);
}
handle_activity_notification(state);
Success
}
TipMessageResult::MessageNotFound => MessageNotFound,
TipMessageResult::CannotTipSelf => CannotTipSelf,
TipMessageResult::MessageSenderMismatch => MessageSenderMismatch,
TipMessageResult::RecipientMismatch => RecipientMismatch,
TipMessageResult::UserNotInGroup => ChannelNotFound,
TipMessageResult::NotAuthorized => NotAuthorized,
TipMessageResult::UserSuspended => UserSuspended,
Expand Down
7 changes: 3 additions & 4 deletions backend/canisters/exchange_bot/impl/src/commands/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::swap_client::SwapClient;
use crate::{mutate_state, RuntimeState};
use exchange_bot_canister::ExchangeId;
use lazy_static::lazy_static;
use ledger_utils::format_crypto_amount;
use ledger_utils::format_crypto_amount_with_symbol;
use rand::Rng;
use regex_lite::{Regex, RegexBuilder};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -118,9 +118,8 @@ impl QuoteCommand {

pub fn build_message_text(&self) -> String {
let mut text = format!(
"Quotes ({} {} to {}):",
format_crypto_amount(self.amount, self.input_token.decimals),
self.input_token.token.token_symbol(),
"Quotes ({} to {}):",
format_crypto_amount_with_symbol(self.amount, self.input_token.decimals, self.input_token.token.token_symbol()),
self.output_token.token.token_symbol()
);
for (exchange_id, status) in self.results.iter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::commands::CommandSubTaskResult;
use ledger_utils::{convert_to_subaccount, format_crypto_amount};
use ledger_utils::{convert_to_subaccount, format_crypto_amount_with_symbol};
use types::icrc1::Account;
use types::{CanisterId, TokenInfo, UserId};

Expand All @@ -18,11 +18,7 @@ pub(crate) async fn check_user_balance(
.map(|a| u128::try_from(a.0).unwrap())
{
Ok(amount) => {
let text = format!(
"{} {}",
format_crypto_amount(amount, token.decimals),
token.token.token_symbol()
);
let text = format_crypto_amount_with_symbol(amount, token.decimals, token.token.token_symbol());
CommandSubTaskResult::Complete(amount, Some(text))
}
Err(error) => CommandSubTaskResult::Failed(format!("{error:?}")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::swap_client::SwapClient;
use exchange_bot_canister::ExchangeId;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use ledger_utils::format_crypto_amount;
use ledger_utils::format_crypto_amount_with_symbol;
use std::future::ready;

pub(crate) async fn get_quotes<C: FnMut(ExchangeId, CommandSubTaskResult<u128>)>(
Expand All @@ -30,11 +30,7 @@ async fn get_quote(client: Box<dyn SwapClient>, amount: u128) -> (ExchangeId, Co
let result = match response {
Ok(amount_out) => {
let output_token = client.output_token();
let text = format!(
"{} {}",
format_crypto_amount(amount_out, output_token.decimals),
output_token.token.token_symbol()
);
let text = format_crypto_amount_with_symbol(amount_out, output_token.decimals, output_token.token.token_symbol());
CommandSubTaskResult::Complete(amount_out, Some(text))
}
Err(error) => CommandSubTaskResult::Failed(format!("{error:?}")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use candid::Principal;
use canister_api_macros::update_msgpack;
use canister_tracing_macros::trace;
use exchange_bot_canister::handle_direct_message::*;
use ledger_utils::format_crypto_amount;
use ledger_utils::format_crypto_amount_with_symbol;
use local_user_index_canister_c2c_client::LookupUserError;
use types::{BotMessage, MessageContent, MessageContentInitial, UserId};

Expand All @@ -28,10 +28,10 @@ fn handle_direct_message_impl(message: MessageContent, state: &mut RuntimeState)

if let MessageContent::Crypto(c) = &message {
let token = c.transfer.token();
response_messages.push(convert_to_message(format!(
"{} {} received",
format_crypto_amount(c.transfer.units(), token.decimals().unwrap_or(8)),
token.token_symbol()
response_messages.push(convert_to_message(format_crypto_amount_with_symbol(
c.transfer.units(),
token.decimals().unwrap_or(8),
token.token_symbol(),
)));
}

Expand Down
5 changes: 5 additions & 0 deletions backend/canisters/group/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [unreleased]

### Added

- Implement tipping messages ([#4420](https://github.com/open-chat-labs/open-chat/pull/4420))
- Implement notifications for message tips ([#4427](https://github.com/open-chat-labs/open-chat/pull/4427))

### Changed

- Disable mentions for messages sent by the ProposalsBot ([#4424](https://github.com/open-chat-labs/open-chat/pull/4424))
Expand Down
6 changes: 4 additions & 2 deletions backend/canisters/group/api/src/updates/c2c_tip_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ use types::{CompletedCryptoTransaction, MessageId, MessageIndex, UserId};

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub struct Args {
pub message_sender: UserId,
pub recipient: UserId,
pub thread_root_message_index: Option<MessageIndex>,
pub message_id: MessageId,
pub transfer: CompletedCryptoTransaction,
pub username: String,
pub display_name: Option<String>,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub enum Response {
Success,
MessageNotFound,
CannotTipSelf,
MessageSenderMismatch,
RecipientMismatch,
NotAuthorized,
GroupFrozen,
UserNotInGroup,
Expand Down
37 changes: 34 additions & 3 deletions backend/canisters/group/impl/src/updates/c2c_tip_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use crate::activity_notifications::handle_activity_notification;
use crate::{mutate_state, run_regular_jobs, RuntimeState};
use canister_api_macros::update_msgpack;
use canister_tracing_macros::trace;
use chat_events::Reader;
use group_canister::c2c_tip_message::{Response::*, *};
use group_chat_core::TipMessageResult;
use ledger_utils::format_crypto_amount_with_symbol;
use types::{EventIndex, GroupMessageTipped, Notification};

#[update_msgpack]
#[trace]
Expand All @@ -20,22 +23,50 @@ fn c2c_tip_message_impl(args: Args, state: &mut RuntimeState) -> Response {

let user_id = state.env.caller().into();
let now = state.env.now();
let token = args.transfer.token();
let amount = args.transfer.units();

match state.data.chat.tip_message(
user_id,
args.message_sender,
args.recipient,
args.thread_root_message_index,
args.message_id,
args.transfer,
now,
) {
TipMessageResult::Success => {
// TODO push notification
if let Some((message_index, message_event_index)) = state
.data
.chat
.events
.events_reader(EventIndex::default(), args.thread_root_message_index, now)
.and_then(|r| {
r.message_event_internal(args.message_id.into())
.map(|e| (e.event.message_index, e.index))
})
{
state.push_notification(
vec![args.recipient],
Notification::GroupMessageTipped(GroupMessageTipped {
chat_id: state.env.canister_id().into(),
thread_root_message_index: args.thread_root_message_index,
message_index,
message_event_index,
group_name: state.data.chat.name.clone(),
tipped_by: user_id,
tipped_by_name: args.username,
tipped_by_display_name: args.display_name,
tip: format_crypto_amount_with_symbol(amount, token.decimals().unwrap_or(8), token.token_symbol()),
group_avatar_id: state.data.chat.avatar.as_ref().map(|a| a.id),
}),
);
}
handle_activity_notification(state);
Success
}
TipMessageResult::MessageNotFound => MessageNotFound,
TipMessageResult::CannotTipSelf => CannotTipSelf,
TipMessageResult::MessageSenderMismatch => MessageSenderMismatch,
TipMessageResult::RecipientMismatch => RecipientMismatch,
TipMessageResult::UserNotInGroup => UserNotInGroup,
TipMessageResult::NotAuthorized => NotAuthorized,
TipMessageResult::UserSuspended => UserSuspended,
Expand Down
2 changes: 2 additions & 0 deletions backend/canisters/user/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

- Add `mention_all_members` group permission ([#4405](https://github.com/open-chat-labs/open-chat/pull/4405))
- Implement tipping messages ([#4420](https://github.com/open-chat-labs/open-chat/pull/4420))
- Implement notifications for message tips ([#4427](https://github.com/open-chat-labs/open-chat/pull/4427))

## [[2.0.852](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.852-user)] - 2023-09-18

Expand Down
3 changes: 3 additions & 0 deletions backend/canisters/user/api/src/updates/c2c_tip_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pub struct Args {
pub thread_root_message_index: Option<MessageIndex>,
pub message_id: MessageId,
pub transfer: CompletedCryptoTransaction,
pub username: String,
pub display_name: Option<String>,
pub user_avatar_id: Option<u128>,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
Expand Down
46 changes: 36 additions & 10 deletions backend/canisters/user/impl/src/updates/c2c_tip_message.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::{mutate_state, run_regular_jobs, RuntimeState};
use canister_api_macros::update_msgpack;
use canister_tracing_macros::trace;
use types::{EventIndex, UserId};
use chat_events::{Reader, TipMessageResult};
use ledger_utils::format_crypto_amount_with_symbol;
use types::{DirectMessageTipped, EventIndex, Notification, UserId};
use user_canister::c2c_tip_message::{Response::*, *};

#[update_msgpack]
Expand All @@ -17,15 +19,39 @@ fn c2c_tip_message_impl(args: Args, state: &mut RuntimeState) -> Response {
if let Some(chat) = state.data.direct_chats.get_mut(&user_id.into()) {
let now = state.env.now();
let my_user_id = state.env.canister_id().into();
chat.events.tip_message(
user_id,
my_user_id,
EventIndex::default(),
args.thread_root_message_index,
args.message_id,
args.transfer,
now,
);
let token = args.transfer.token();
let amount = args.transfer.units();

if matches!(
chat.events.tip_message(
user_id,
my_user_id,
EventIndex::default(),
args.thread_root_message_index,
args.message_id,
args.transfer,
now,
),
TipMessageResult::Success
) {
if let Some(event) = chat
.events
.main_events_reader(now)
.message_event_internal(args.message_id.into())
{
let notification = Notification::DirectMessageTipped(DirectMessageTipped {
them: user_id,
thread_root_message_index: args.thread_root_message_index,
message_index: event.event.message_index,
message_event_index: event.index,
username: args.username,
display_name: args.display_name,
tip: format_crypto_amount_with_symbol(amount, token.decimals().unwrap_or(8), token.token_symbol()),
user_avatar_id: args.user_avatar_id,
});
state.push_notification(my_user_id, notification);
}
}
}
Success
}
Loading

0 comments on commit 8db9d2c

Please sign in to comment.