diff --git a/backend/canisters/community/CHANGELOG.md b/backend/canisters/community/CHANGELOG.md index 8797dce30e..6aa6dbcc66 100644 --- a/backend/canisters/community/CHANGELOG.md +++ b/backend/canisters/community/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Refund remaining prizes early if message gets deleted ([#4708](https://github.com/open-chat-labs/open-chat/pull/4708)) +- Add `events_ttl_last_updated` to chat summaries ([#4711](https://github.com/open-chat-labs/open-chat/pull/4711)) ## [[2.0.921](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.921-community)] - 2023-11-02 diff --git a/backend/canisters/community/impl/src/model/channels.rs b/backend/canisters/community/impl/src/model/channels.rs index 1f9420d5d2..fce5e08918 100644 --- a/backend/canisters/community/impl/src/model/channels.rs +++ b/backend/canisters/community/impl/src/model/channels.rs @@ -209,6 +209,7 @@ impl Channel { let main_events_reader = chat.events.visible_main_events_reader(min_visible_event_index); let latest_message = if can_view_latest_message { main_events_reader.latest_message_event(user_id) } else { None }; + let events_ttl = chat.events.get_events_time_to_live(); let latest_message_sender_display_name = latest_message .as_ref() @@ -257,7 +258,8 @@ impl Channel { permissions_v2: chat.permissions.value.clone(), metrics: chat.events.metrics().hydrate(), date_last_pinned: chat.date_last_pinned, - events_ttl: chat.events.get_events_time_to_live().value, + events_ttl: events_ttl.value, + events_ttl_last_updated: events_ttl.timestamp, gate: chat.gate.value.clone(), membership, }) @@ -339,6 +341,7 @@ impl Channel { metrics: Some(self.chat.events.metrics().hydrate()), date_last_pinned: updates.date_last_pinned, events_ttl: updates.events_ttl, + events_ttl_last_updated: updates.events_ttl_last_updated, gate: updates.gate, membership, }) diff --git a/backend/canisters/group/CHANGELOG.md b/backend/canisters/group/CHANGELOG.md index e4b2e416e8..ffda50f303 100644 --- a/backend/canisters/group/CHANGELOG.md +++ b/backend/canisters/group/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Refund remaining prizes early if message gets deleted ([#4708](https://github.com/open-chat-labs/open-chat/pull/4708)) +- Add `events_ttl_last_updated` to chat summaries ([#4711](https://github.com/open-chat-labs/open-chat/pull/4711)) ## [[2.0.922](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.922-group)] - 2023-11-02 diff --git a/backend/canisters/group/impl/src/lib.rs b/backend/canisters/group/impl/src/lib.rs index 8e090c7816..f4fcab86d5 100644 --- a/backend/canisters/group/impl/src/lib.rs +++ b/backend/canisters/group/impl/src/lib.rs @@ -105,6 +105,7 @@ impl RuntimeState { let min_visible_event_index = member.min_visible_event_index(); let min_visible_message_index = member.min_visible_message_index(); let main_events_reader = chat.events.visible_main_events_reader(min_visible_event_index); + let events_ttl = chat.events.get_events_time_to_live(); GroupCanisterGroupChatSummary { chat_id: self.env.canister_id().into(), @@ -142,7 +143,8 @@ impl RuntimeState { frozen: self.data.frozen.value.clone(), wasm_version: BuildVersion::default(), date_last_pinned: chat.date_last_pinned, - events_ttl: chat.events.get_events_time_to_live().value, + events_ttl: events_ttl.value, + events_ttl_last_updated: events_ttl.timestamp, gate: chat.gate.value.clone(), rules_accepted: member .rules_accepted diff --git a/backend/canisters/group/impl/src/queries/public_summary.rs b/backend/canisters/group/impl/src/queries/public_summary.rs index 4cc1619c27..9026280d4c 100644 --- a/backend/canisters/group/impl/src/queries/public_summary.rs +++ b/backend/canisters/group/impl/src/queries/public_summary.rs @@ -20,6 +20,7 @@ fn public_summary_impl(args: Args, state: &RuntimeState) -> Response { let is_public = state.data.chat.is_public.value; let data = &state.data; let events_reader = data.chat.events.main_events_reader(); + let events_ttl = data.chat.events.get_events_time_to_live(); // You can't see private group messages unless you are a member of the group let latest_message = if is_public || state.data.get_member(caller).is_some() { @@ -42,7 +43,8 @@ fn public_summary_impl(args: Args, state: &RuntimeState) -> Response { participant_count: data.chat.members.len(), is_public, frozen: data.frozen.value.clone(), - events_ttl: data.chat.events.get_events_time_to_live().value, + events_ttl: events_ttl.value, + events_ttl_last_updated: events_ttl.timestamp, gate: data.chat.gate.value.clone(), wasm_version: BuildVersion::default(), }; diff --git a/backend/canisters/group/impl/src/queries/summary_updates.rs b/backend/canisters/group/impl/src/queries/summary_updates.rs index af357a05d2..62f1eb65ca 100644 --- a/backend/canisters/group/impl/src/queries/summary_updates.rs +++ b/backend/canisters/group/impl/src/queries/summary_updates.rs @@ -81,6 +81,7 @@ fn summary_updates_impl(args: Args, state: &RuntimeState) -> Response { wasm_version: None, date_last_pinned: updates.date_last_pinned, events_ttl: updates.events_ttl, + events_ttl_last_updated: updates.events_ttl_last_updated, gate: updates.gate, rules_accepted: member .rules_accepted diff --git a/backend/canisters/group_index/CHANGELOG.md b/backend/canisters/group_index/CHANGELOG.md index 4b27a1681f..3556c945ad 100644 --- a/backend/canisters/group_index/CHANGELOG.md +++ b/backend/canisters/group_index/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] +### Changed + +- Add `events_ttl_last_updated` to chat summaries ([#4711](https://github.com/open-chat-labs/open-chat/pull/4711)) + ## [[2.0.926](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.926-group_index)] - 2023-11-03 ### Changed diff --git a/backend/canisters/group_index/impl/src/model/cached_hot_groups.rs b/backend/canisters/group_index/impl/src/model/cached_hot_groups.rs index 4638902111..d819bcb4ef 100644 --- a/backend/canisters/group_index/impl/src/model/cached_hot_groups.rs +++ b/backend/canisters/group_index/impl/src/model/cached_hot_groups.rs @@ -36,7 +36,6 @@ impl CachedHotGroups { } #[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(from = "CachedPublicGroupSummaryCombined")] pub struct CachedPublicGroupSummary { pub chat_id: ChatId, pub last_updated: TimestampMillis, @@ -45,41 +44,11 @@ pub struct CachedPublicGroupSummary { pub latest_message_index: Option, pub participant_count: u32, pub events_ttl: Option, - pub gate: Option, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct CachedPublicGroupSummaryCombined { - pub chat_id: ChatId, - pub last_updated: TimestampMillis, - pub latest_message: Option>, - pub latest_event_index: EventIndex, #[serde(default)] - pub latest_message_index: Option, - pub participant_count: u32, - pub events_ttl: Option, + pub events_ttl_last_updated: TimestampMillis, pub gate: Option, } -impl From for CachedPublicGroupSummary { - fn from(value: CachedPublicGroupSummaryCombined) -> Self { - let latest_message_index = value - .latest_message_index - .or_else(|| value.latest_message.as_ref().map(|m| m.event.message_index)); - - CachedPublicGroupSummary { - chat_id: value.chat_id, - last_updated: value.last_updated, - latest_message: value.latest_message, - latest_event_index: value.latest_event_index, - latest_message_index, - participant_count: value.participant_count, - events_ttl: value.events_ttl, - gate: value.gate, - } - } -} - impl From for CachedPublicGroupSummary { fn from(summary: PublicGroupSummary) -> Self { CachedPublicGroupSummary { @@ -90,6 +59,7 @@ impl From for CachedPublicGroupSummary { latest_message_index: summary.latest_message_index, participant_count: summary.participant_count, events_ttl: summary.events_ttl, + events_ttl_last_updated: summary.events_ttl_last_updated, gate: summary.gate, } } diff --git a/backend/canisters/group_index/impl/src/model/public_groups.rs b/backend/canisters/group_index/impl/src/model/public_groups.rs index 75f14d545b..123ba0dfe2 100644 --- a/backend/canisters/group_index/impl/src/model/public_groups.rs +++ b/backend/canisters/group_index/impl/src/model/public_groups.rs @@ -98,6 +98,7 @@ impl PublicGroups { is_public: true, frozen: None, events_ttl: summary.events_ttl, + events_ttl_last_updated: summary.events_ttl_last_updated, gate: summary.gate, wasm_version: BuildVersion::default(), }) diff --git a/backend/canisters/user/CHANGELOG.md b/backend/canisters/user/CHANGELOG.md index d34db47438..aa9485fd46 100644 --- a/backend/canisters/user/CHANGELOG.md +++ b/backend/canisters/user/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] +### Changed + +- Add `events_ttl_last_updated` to chat summaries ([#4711](https://github.com/open-chat-labs/open-chat/pull/4711)) + ## [[2.0.923](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.923-user)] - 2023-11-03 ### Added diff --git a/backend/canisters/user/impl/src/model/direct_chat.rs b/backend/canisters/user/impl/src/model/direct_chat.rs index c02bc7f42d..cf986e5d3f 100644 --- a/backend/canisters/user/impl/src/model/direct_chat.rs +++ b/backend/canisters/user/impl/src/model/direct_chat.rs @@ -80,6 +80,7 @@ impl DirectChat { pub fn to_summary(&self, my_user_id: UserId) -> DirectChatSummary { let events_reader = self.events.main_events_reader(); + let events_ttl = self.events.get_events_time_to_live(); DirectChatSummary { them: self.them, @@ -98,7 +99,8 @@ impl DirectChat { .map(|m| m.hydrate()) .unwrap_or_default(), archived: self.archived.value, - events_ttl: self.events.get_events_time_to_live().value, + events_ttl: events_ttl.value, + events_ttl_last_updated: events_ttl.timestamp, } } @@ -111,6 +113,7 @@ impl DirectChat { let latest_message_index = if has_new_events { events_reader.latest_message_index() } else { None }; let notifications_muted = self.notifications_muted.if_set_after(updates_since).copied(); let metrics = if has_new_events { Some(self.events.metrics().hydrate()) } else { None }; + let events_ttl = self.events.get_events_time_to_live(); let updated_events: Vec<_> = self .events .iter_recently_updated_events() @@ -134,12 +137,11 @@ impl DirectChat { .user_metrics(&my_user_id, Some(updates_since)) .map(|m| m.hydrate()), archived: self.archived.if_set_after(updates_since).copied(), - events_ttl: self - .events - .get_events_time_to_live() + events_ttl: events_ttl .if_set_after(updates_since) .copied() .map_or(OptionUpdate::NoChange, OptionUpdate::from_update), + events_ttl_last_updated: (events_ttl.timestamp > updates_since).then_some(events_ttl.timestamp), } } } diff --git a/backend/canisters/user/impl/src/queries/initial_state.rs b/backend/canisters/user/impl/src/queries/initial_state.rs index 202909d51f..0e347ece21 100644 --- a/backend/canisters/user/impl/src/queries/initial_state.rs +++ b/backend/canisters/user/impl/src/queries/initial_state.rs @@ -128,6 +128,7 @@ fn hydrate_cached_summary(cached: &GroupCanisterGroupChatSummary, user_details: date_last_pinned: cached.date_last_pinned, date_read_pinned: user_details.messages_read.date_read_pinned.value, events_ttl: cached.events_ttl, + events_ttl_last_updated: cached.events_ttl_last_updated, gate: cached.gate.clone(), rules_accepted: cached.rules_accepted, } diff --git a/backend/libraries/group_chat_core/src/lib.rs b/backend/libraries/group_chat_core/src/lib.rs index 07b1af13a7..7a988e29a8 100644 --- a/backend/libraries/group_chat_core/src/lib.rs +++ b/backend/libraries/group_chat_core/src/lib.rs @@ -158,6 +158,7 @@ impl GroupChatCore { let mentions = member .map(|m| m.most_recent_mentions(Some(since), &self.events)) .unwrap_or_default(); + let events_ttl = self.events.get_events_time_to_live(); let mut updated_events: Vec<_> = self .events .iter_recently_updated_events() @@ -205,12 +206,11 @@ impl GroupChatCore { updated_events, is_public: self.is_public.if_set_after(since).copied(), date_last_pinned: self.date_last_pinned.filter(|ts| *ts > since), - events_ttl: self - .events - .get_events_time_to_live() + events_ttl: events_ttl .if_set_after(since) .copied() .map_or(OptionUpdate::NoChange, OptionUpdate::from_update), + events_ttl_last_updated: (events_ttl.timestamp > since).then_some(events_ttl.timestamp), gate: self .gate .if_set_after(since) @@ -1867,6 +1867,7 @@ pub struct SummaryUpdates { pub is_public: Option, pub date_last_pinned: Option, pub events_ttl: OptionUpdate, + pub events_ttl_last_updated: Option, pub gate: OptionUpdate, pub rules_changed: bool, } diff --git a/backend/libraries/types/can.did b/backend/libraries/types/can.did index 7a9e66efcd..bd846a6b57 100644 --- a/backend/libraries/types/can.did +++ b/backend/libraries/types/can.did @@ -130,6 +130,7 @@ type DirectChatSummary = record { my_metrics : ChatMetrics; archived : bool; events_ttl : opt Milliseconds; + events_ttl_last_updated : TimestampMillis; }; type DirectChatSummaryUpdates = record { @@ -146,6 +147,7 @@ type DirectChatSummaryUpdates = record { my_metrics : opt ChatMetrics; archived : opt bool; events_ttl : EventsTimeToLiveUpdate; + events_ttl_last_updated : opt TimestampMillis; }; type DirectMessageNotification = record { @@ -275,6 +277,7 @@ type GroupChatSummary = record { date_last_pinned : opt TimestampMillis; date_read_pinned : opt TimestampMillis; events_ttl : opt Milliseconds; + events_ttl_last_updated : TimestampMillis; gate : opt AccessGate; rules_accepted : bool; }; @@ -306,6 +309,7 @@ type GroupCanisterGroupChatSummary = record { wasm_version : BuildVersion; date_last_pinned : opt TimestampMillis; events_ttl : opt Milliseconds; + events_ttl_last_updated : TimestampMillis; gate : opt AccessGate; rules_accepted : bool; }; @@ -335,6 +339,7 @@ type GroupCanisterGroupChatSummaryUpdates = record { wasm_version : opt BuildVersion; date_last_pinned : opt TimestampMillis; events_ttl : EventsTimeToLiveUpdate; + events_ttl_last_updated : opt TimestampMillis; gate : AccessGateUpdate; rules_accepted : opt bool; }; @@ -392,6 +397,7 @@ type CommunityCanisterChannelSummary = record { metrics : ChatMetrics; date_last_pinned : opt TimestampMillis; events_ttl : opt Milliseconds; + events_ttl_last_updated : TimestampMillis; gate : opt AccessGate; membership : opt ChannelMembership; }; @@ -453,6 +459,7 @@ type CommunityCanisterChannelSummaryUpdates = record { metrics : opt ChatMetrics; date_last_pinned : opt TimestampMillis; events_ttl : EventsTimeToLiveUpdate; + events_ttl_last_updated : opt TimestampMillis; gate : AccessGateUpdate; membership : opt ChannelMembershipUpdates; }; @@ -714,6 +721,7 @@ type PublicGroupSummary = record { is_public : bool; frozen : opt FrozenGroupInfo; events_ttl : opt Milliseconds; + events_ttl_last_updated : TimestampMillis; gate : opt AccessGate; wasm_version : BuildVersion; }; diff --git a/backend/libraries/types/src/channel_summary.rs b/backend/libraries/types/src/channel_summary.rs index c36834d7af..3c5ca9c53a 100644 --- a/backend/libraries/types/src/channel_summary.rs +++ b/backend/libraries/types/src/channel_summary.rs @@ -26,6 +26,8 @@ pub struct CommunityCanisterChannelSummary { pub metrics: ChatMetrics, pub date_last_pinned: Option, pub events_ttl: Option, + #[serde(default)] + pub events_ttl_last_updated: TimestampMillis, pub gate: Option, pub membership: Option, } @@ -60,6 +62,8 @@ pub struct CommunityCanisterChannelSummaryUpdates { pub metrics: Option, pub date_last_pinned: Option, pub events_ttl: OptionUpdate, + #[serde(default)] + pub events_ttl_last_updated: Option, pub gate: OptionUpdate, pub membership: Option, } diff --git a/backend/libraries/types/src/chat_summary.rs b/backend/libraries/types/src/chat_summary.rs index cf10b1e9df..dafa2e032d 100644 --- a/backend/libraries/types/src/chat_summary.rs +++ b/backend/libraries/types/src/chat_summary.rs @@ -24,6 +24,8 @@ pub struct DirectChatSummary { pub my_metrics: ChatMetrics, pub archived: bool, pub events_ttl: Option, + #[serde(default)] + pub events_ttl_last_updated: TimestampMillis, } impl DirectChatSummary { @@ -64,6 +66,8 @@ pub struct GroupChatSummary { pub date_last_pinned: Option, pub date_read_pinned: Option, pub events_ttl: Option, + #[serde(default)] + pub events_ttl_last_updated: TimestampMillis, pub gate: Option, pub rules_accepted: bool, } @@ -83,6 +87,8 @@ pub struct DirectChatSummaryUpdates { pub my_metrics: Option, pub archived: Option, pub events_ttl: OptionUpdate, + #[serde(default)] + pub events_ttl_last_updated: Option, } // TODO: This type is used in the response from group::public_summary and group_index::recommended_groups @@ -105,11 +111,12 @@ pub struct PublicGroupSummary { pub is_public: bool, pub frozen: Option, pub events_ttl: Option, + #[serde(default)] + pub events_ttl_last_updated: TimestampMillis, pub gate: Option, } #[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -#[serde(from = "GroupCanisterGroupChatSummaryCombined")] pub struct GroupCanisterGroupChatSummary { pub chat_id: ChatId, pub last_updated: TimestampMillis, @@ -137,82 +144,12 @@ pub struct GroupCanisterGroupChatSummary { pub frozen: Option, pub date_last_pinned: Option, pub events_ttl: Option, - pub gate: Option, - pub rules_accepted: bool, -} - -#[derive(CandidType, Serialize, Deserialize, Clone, Debug)] -pub struct GroupCanisterGroupChatSummaryCombined { - pub chat_id: ChatId, - pub last_updated: TimestampMillis, - pub name: String, - pub description: String, - pub subtype: Option, - pub avatar_id: Option, - pub is_public: bool, - pub history_visible_to_new_joiners: bool, - pub min_visible_event_index: EventIndex, - pub min_visible_message_index: MessageIndex, - pub latest_message: Option>, - pub latest_event_index: EventIndex, #[serde(default)] - pub latest_message_index: Option, - pub joined: TimestampMillis, - pub participant_count: u32, - pub role: GroupRole, - pub mentions: Vec, - pub wasm_version: BuildVersion, - pub permissions_v2: GroupPermissions, - pub notifications_muted: bool, - pub metrics: ChatMetrics, - pub my_metrics: ChatMetrics, - pub latest_threads: Vec, - pub frozen: Option, - pub date_last_pinned: Option, - pub events_ttl: Option, + pub events_ttl_last_updated: TimestampMillis, pub gate: Option, pub rules_accepted: bool, } -impl From for GroupCanisterGroupChatSummary { - fn from(value: GroupCanisterGroupChatSummaryCombined) -> Self { - let latest_message_index = value - .latest_message_index - .or_else(|| value.latest_message.as_ref().map(|m| m.event.message_index)); - - GroupCanisterGroupChatSummary { - chat_id: value.chat_id, - last_updated: value.last_updated, - name: value.name, - description: value.description, - subtype: value.subtype, - avatar_id: value.avatar_id, - is_public: value.is_public, - history_visible_to_new_joiners: value.history_visible_to_new_joiners, - min_visible_event_index: value.min_visible_event_index, - min_visible_message_index: value.min_visible_message_index, - latest_message: value.latest_message, - latest_event_index: value.latest_event_index, - latest_message_index, - joined: value.joined, - participant_count: value.participant_count, - role: value.role, - mentions: value.mentions, - wasm_version: value.wasm_version, - permissions_v2: value.permissions_v2, - notifications_muted: value.notifications_muted, - metrics: value.metrics, - my_metrics: value.my_metrics, - latest_threads: value.latest_threads, - frozen: value.frozen, - date_last_pinned: value.date_last_pinned, - events_ttl: value.events_ttl, - gate: value.gate, - rules_accepted: value.rules_accepted, - } - } -} - impl GroupCanisterGroupChatSummary { pub fn merge(self, updates: GroupCanisterGroupChatSummaryUpdates) -> Self { if self.chat_id != updates.chat_id { @@ -269,6 +206,7 @@ impl GroupCanisterGroupChatSummary { frozen: updates.frozen.apply_to(self.frozen), date_last_pinned: updates.date_last_pinned.or(self.date_last_pinned), events_ttl: updates.events_ttl.apply_to(self.events_ttl), + events_ttl_last_updated: updates.events_ttl_last_updated.unwrap_or(self.events_ttl_last_updated), gate: updates.gate.apply_to(self.gate), rules_accepted: updates.rules_accepted.unwrap_or(self.rules_accepted), } @@ -301,6 +239,8 @@ pub struct GroupCanisterGroupChatSummaryUpdates { pub frozen: OptionUpdate, pub date_last_pinned: Option, pub events_ttl: OptionUpdate, + #[serde(default)] + pub events_ttl_last_updated: Option, pub gate: OptionUpdate, pub rules_accepted: Option, }