diff --git a/backend/canisters/user_index/CHANGELOG.md b/backend/canisters/user_index/CHANGELOG.md index 55b1f53f85..aaddd7f3a4 100644 --- a/backend/canisters/user_index/CHANGELOG.md +++ b/backend/canisters/user_index/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Implement `register_bot` including bot schema ([#6928](https://github.com/open-chat-labs/open-chat/pull/6928)) - Implement `explore_bots` ([#6932](https://github.com/open-chat-labs/open-chat/pull/6932)) +- Implement `bot_updates` ([#6934](https://github.com/open-chat-labs/open-chat/pull/6934)) ## [[2.0.1469](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1469-user_index)] - 2024-11-25 diff --git a/backend/canisters/user_index/api/can.did b/backend/canisters/user_index/api/can.did index 2f703036ab..bbf1b8f05d 100644 --- a/backend/canisters/user_index/api/can.did +++ b/backend/canisters/user_index/api/can.did @@ -10,6 +10,28 @@ type PublicKeyResponse = variant { NotInitialised; }; +type BotUpdatesArgs = record { + updated_since : TimestampMillis; +}; + +type BotUpdatesResponse = variant { + Success : record { + added_or_updated: vec record { + id: UserId; + owner: UserId; + name: text; + avatar_id: opt nat; + endpoint: text; + description: text; + commands: vec SlashCommandSchema; + last_updated : TimestampMillis; + }; + deleted: vec UserId; + timestamp: TimestampMillis; + }; + SuccessNoUpdates; +}; + type CheckUsernameArgs = record { username : text; is_bot : bool; @@ -92,6 +114,7 @@ type ExploreBotsResponse = variant { type BotMatch = record { id : UserId; score : nat32; + owner : UserId; name : text; description : text; avatar_id : opt nat; @@ -175,8 +198,6 @@ type ExternalAchievementsResponse = variant { Success : record { last_updated: TimestampMillis; added_or_updated : vec ExternalAchievement; - achievements_added : vec ExternalAchievement; - achievements_removed : vec ExternalAchievement; }; SuccessNoUpdates; }; @@ -258,6 +279,7 @@ type AwardExternalAchievementResponse = variant { service : { // Queries + bot_updates : (BotUpdatesArgs) -> (BotUpdatesResponse) query; check_username : (CheckUsernameArgs) -> (CheckUsernameResponse) query; chit_leaderboard : (EmptyArgs) -> (ChitLeaderboardResponse) query; current_user : (EmptyArgs) -> (CurrentUserResponse) query; diff --git a/backend/canisters/user_index/api/src/main.rs b/backend/canisters/user_index/api/src/main.rs index 6bdf4e009f..b7ef04a863 100644 --- a/backend/canisters/user_index/api/src/main.rs +++ b/backend/canisters/user_index/api/src/main.rs @@ -3,6 +3,7 @@ use std::env; use ts_export::generate_ts_method; fn main() { + generate_candid_method!(user_index, bot_updates, query); generate_candid_method!(user_index, check_username, query); generate_candid_method!(user_index, chit_leaderboard, query); generate_candid_method!(user_index, current_user, query); diff --git a/backend/canisters/user_index/api/src/queries/bot_updates.rs b/backend/canisters/user_index/api/src/queries/bot_updates.rs new file mode 100644 index 0000000000..690fb2d2b1 --- /dev/null +++ b/backend/canisters/user_index/api/src/queries/bot_updates.rs @@ -0,0 +1,38 @@ +use candid::CandidType; +use serde::{Deserialize, Serialize}; +use ts_export::ts_export; +use types::{SlashCommandSchema, TimestampMillis, UserId}; + +#[ts_export(user_index, bot_updates)] +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub struct Args { + pub updated_since: TimestampMillis, +} + +#[ts_export(user_index, bot_updates)] +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub enum Response { + Success(SuccessResult), + SuccessNoUpdates, +} + +#[ts_export(user_index, bot_updates)] +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub struct SuccessResult { + pub added_or_updated: Vec, + pub deleted: Vec, + pub timestamp: TimestampMillis, +} + +#[ts_export(user_index, bot_updates)] +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub struct BotSchema { + pub id: UserId, + pub owner: UserId, + pub name: String, + pub avatar_id: Option, + pub endpoint: String, + pub description: String, + pub commands: Vec, + pub last_updated: TimestampMillis, +} diff --git a/backend/canisters/user_index/api/src/queries/explore_bots.rs b/backend/canisters/user_index/api/src/queries/explore_bots.rs index 6f39fe2e89..ade7e9639d 100644 --- a/backend/canisters/user_index/api/src/queries/explore_bots.rs +++ b/backend/canisters/user_index/api/src/queries/explore_bots.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use ts_export::ts_export; use types::BotMatch; -#[ts_export(group_index, explore_communities)] +#[ts_export(group_index, explore_bots)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct Args { pub search_term: Option, @@ -11,7 +11,7 @@ pub struct Args { pub page_size: u8, } -#[ts_export(group_index, explore_communities)] +#[ts_export(group_index, explore_bots)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub enum Response { Success(SuccessResult), @@ -20,7 +20,7 @@ pub enum Response { InvalidTerm, } -#[ts_export(group_index, explore_communities)] +#[ts_export(group_index, explore_bots)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct SuccessResult { pub matches: Vec, diff --git a/backend/canisters/user_index/api/src/queries/external_achievements.rs b/backend/canisters/user_index/api/src/queries/external_achievements.rs index b11677a198..2eb7219486 100644 --- a/backend/canisters/user_index/api/src/queries/external_achievements.rs +++ b/backend/canisters/user_index/api/src/queries/external_achievements.rs @@ -21,10 +21,6 @@ pub enum Response { pub struct SuccessResult { pub last_updated: TimestampMillis, pub added_or_updated: Vec, - // TODO: Remove after FE updated to use added_or_updated - pub achievements_added: Vec, - // TODO: Remove after FE updated to use added_or_updated - pub achievements_removed: Vec, } #[ts_export(user_index, external_achievements)] diff --git a/backend/canisters/user_index/api/src/queries/mod.rs b/backend/canisters/user_index/api/src/queries/mod.rs index ac8eeab638..f0630161f9 100644 --- a/backend/canisters/user_index/api/src/queries/mod.rs +++ b/backend/canisters/user_index/api/src/queries/mod.rs @@ -1,3 +1,4 @@ +pub mod bot_updates; pub mod c2c_lookup_user; pub mod check_username; pub mod chit_leaderboard; diff --git a/backend/canisters/user_index/api/src/queries/users.rs b/backend/canisters/user_index/api/src/queries/users.rs index fce026d3f7..0c6d3fb2e2 100644 --- a/backend/canisters/user_index/api/src/queries/users.rs +++ b/backend/canisters/user_index/api/src/queries/users.rs @@ -8,7 +8,6 @@ use types::{CurrentUserSummary, TimestampMillis, UserId, UserSummaryV2}; pub struct Args { pub user_groups: Vec, pub users_suspended_since: Option, - //pub bots_updated_since: Option, } #[ts_export(user_index, users)] diff --git a/backend/canisters/user_index/impl/src/model/user_map.rs b/backend/canisters/user_index/impl/src/model/user_map.rs index 5d0620a187..d680070464 100644 --- a/backend/canisters/user_index/impl/src/model/user_map.rs +++ b/backend/canisters/user_index/impl/src/model/user_map.rs @@ -56,6 +56,7 @@ impl Bot { BotMatch { id, score, + owner: self.owner, name: self.name.clone(), description: self.description.clone(), avatar_id: self.avatar.as_ref().map(|a| a.id), @@ -351,6 +352,10 @@ impl UserMap { self.users.values() } + pub fn iter_bots(&self) -> impl Iterator { + self.bots.iter() + } + pub fn len(&self) -> usize { self.users.len() } diff --git a/backend/canisters/user_index/impl/src/queries/bot_updates.rs b/backend/canisters/user_index/impl/src/queries/bot_updates.rs new file mode 100644 index 0000000000..f107a66fb2 --- /dev/null +++ b/backend/canisters/user_index/impl/src/queries/bot_updates.rs @@ -0,0 +1,37 @@ +use crate::{read_state, RuntimeState}; +use canister_api_macros::query; +use user_index_canister::bot_updates::{Response::*, *}; + +#[query(candid = true, msgpack = true)] +fn bot_updates(args: Args) -> Response { + read_state(|state| bot_updates_impl(args, state)) +} + +fn bot_updates_impl(args: Args, state: &RuntimeState) -> Response { + let added_or_updated: Vec<_> = state + .data + .users + .iter_bots() + .filter(|(_, b)| b.last_updated > args.updated_since) + .map(|(id, b)| BotSchema { + id: *id, + owner: b.owner, + name: b.name.clone(), + avatar_id: b.avatar.as_ref().map(|a| a.id), + endpoint: b.endpoint.clone(), + description: b.description.clone(), + commands: b.commands.clone(), + last_updated: b.last_updated, + }) + .collect(); + + if let Some(timestamp) = added_or_updated.iter().map(|b| b.last_updated).max() { + Success(SuccessResult { + added_or_updated, + deleted: Vec::new(), + timestamp, + }) + } else { + SuccessNoUpdates + } +} diff --git a/backend/canisters/user_index/impl/src/queries/external_achievements.rs b/backend/canisters/user_index/impl/src/queries/external_achievements.rs index 0db46e2a90..42bf53d5ae 100644 --- a/backend/canisters/user_index/impl/src/queries/external_achievements.rs +++ b/backend/canisters/user_index/impl/src/queries/external_achievements.rs @@ -11,7 +11,6 @@ fn external_achievements(args: Args) -> Response { fn external_achievements_impl(args: Args, state: &RuntimeState) -> Response { let mut added_or_updated = Vec::new(); - let mut achievements_added = Vec::new(); let mut last_updated: TimestampMillis = 0; for (id, achievement) in state.data.external_achievements.iter() { @@ -35,10 +34,6 @@ fn external_achievements_impl(args: Args, state: &RuntimeState) -> Response { budget_exhausted: achievement.budget_exhausted.is_some(), }; - if add { - achievements_added.push(a.clone()); - } - added_or_updated.push(a); } } @@ -49,8 +44,6 @@ fn external_achievements_impl(args: Args, state: &RuntimeState) -> Response { Success(SuccessResult { last_updated, added_or_updated, - achievements_added, - achievements_removed: Vec::new(), }) } } diff --git a/backend/canisters/user_index/impl/src/queries/mod.rs b/backend/canisters/user_index/impl/src/queries/mod.rs index 15d5e011e1..949b5309df 100644 --- a/backend/canisters/user_index/impl/src/queries/mod.rs +++ b/backend/canisters/user_index/impl/src/queries/mod.rs @@ -1,3 +1,4 @@ +pub mod bot_updates; pub mod c2c_lookup_user; pub mod check_username; pub mod chit_leaderboard; diff --git a/backend/libraries/types/src/bots.rs b/backend/libraries/types/src/bots.rs index b025fa1aee..2f4aace611 100644 --- a/backend/libraries/types/src/bots.rs +++ b/backend/libraries/types/src/bots.rs @@ -80,6 +80,7 @@ pub struct BotMatch { pub score: u32, pub name: String, pub description: String, + pub owner: UserId, pub avatar_id: Option, pub banner_id: Option, pub commands: Vec,