diff --git a/backend/canisters/community/api/src/main.rs b/backend/canisters/community/api/src/main.rs index 4fd909fa3c..5b1705a23e 100644 --- a/backend/canisters/community/api/src/main.rs +++ b/backend/canisters/community/api/src/main.rs @@ -137,6 +137,7 @@ fn main() { generate_ts_method!(community, undelete_messages); generate_ts_method!(community, unfollow_thread); generate_ts_method!(community, unpin_message); + generate_ts_method!(community, update_bot); generate_ts_method!(community, update_channel); generate_ts_method!(community, update_community); generate_ts_method!(community, update_user_group); diff --git a/backend/canisters/community/api/src/updates/update_bot.rs b/backend/canisters/community/api/src/updates/update_bot.rs index 10b34fd918..7aaf67de3f 100644 --- a/backend/canisters/community/api/src/updates/update_bot.rs +++ b/backend/canisters/community/api/src/updates/update_bot.rs @@ -3,14 +3,14 @@ use serde::{Deserialize, Serialize}; use ts_export::ts_export; use types::{SlashCommandPermissions, UserId}; -#[ts_export(community, add_bot)] +#[ts_export(community, update_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct Args { pub bot_id: UserId, pub granted_permissions: SlashCommandPermissions, } -#[ts_export(community, add_bot)] +#[ts_export(community, update_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub enum Response { Success, diff --git a/backend/canisters/group/api/src/main.rs b/backend/canisters/group/api/src/main.rs index d92e44b161..e87ba6b443 100644 --- a/backend/canisters/group/api/src/main.rs +++ b/backend/canisters/group/api/src/main.rs @@ -109,6 +109,7 @@ fn main() { generate_ts_method!(group, undelete_messages); generate_ts_method!(group, unfollow_thread); generate_ts_method!(group, unpin_message); + generate_ts_method!(group, update_bot); generate_ts_method!(group, update_group_v2); candid::export_service!(); diff --git a/backend/canisters/group/api/src/updates/add_bot.rs b/backend/canisters/group/api/src/updates/add_bot.rs index 7116a679cc..042e7f3f4d 100644 --- a/backend/canisters/group/api/src/updates/add_bot.rs +++ b/backend/canisters/group/api/src/updates/add_bot.rs @@ -3,14 +3,14 @@ use serde::{Deserialize, Serialize}; use ts_export::ts_export; use types::{SlashCommandPermissions, UserId}; -#[ts_export(community, add_bot)] +#[ts_export(group, add_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct Args { pub bot_id: UserId, pub granted_permissions: SlashCommandPermissions, } -#[ts_export(community, add_bot)] +#[ts_export(group, add_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub enum Response { Success, diff --git a/backend/canisters/group/api/src/updates/remove_bot.rs b/backend/canisters/group/api/src/updates/remove_bot.rs index d4200825c1..6e47685e9d 100644 --- a/backend/canisters/group/api/src/updates/remove_bot.rs +++ b/backend/canisters/group/api/src/updates/remove_bot.rs @@ -3,13 +3,13 @@ use serde::{Deserialize, Serialize}; use ts_export::ts_export; use types::UserId; -#[ts_export(community, remove_bot)] +#[ts_export(group, remove_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct Args { pub bot_id: UserId, } -#[ts_export(community, remove_bot)] +#[ts_export(group, remove_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub enum Response { Success, diff --git a/backend/canisters/group/api/src/updates/update_bot.rs b/backend/canisters/group/api/src/updates/update_bot.rs index 4408a8e69c..35730ad2bc 100644 --- a/backend/canisters/group/api/src/updates/update_bot.rs +++ b/backend/canisters/group/api/src/updates/update_bot.rs @@ -3,14 +3,14 @@ use serde::{Deserialize, Serialize}; use ts_export::ts_export; use types::{SlashCommandPermissions, UserId}; -#[ts_export(community, add_bot)] +#[ts_export(group, update_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub struct Args { pub bot_id: UserId, pub granted_permissions: SlashCommandPermissions, } -#[ts_export(community, add_bot)] +#[ts_export(group, update_bot)] #[derive(CandidType, Serialize, Deserialize, Debug)] pub enum Response { Success, diff --git a/frontend/app/src/components/bots/BotExplorer.svelte b/frontend/app/src/components/bots/BotExplorer.svelte index dba9a35ce2..7cfadf5e69 100644 --- a/frontend/app/src/components/bots/BotExplorer.svelte +++ b/frontend/app/src/components/bots/BotExplorer.svelte @@ -1,5 +1,10 @@ {#if showing} - (showing = false)} bot={match} /> + (showing = false)} bot={match} /> {/if} diff --git a/frontend/app/src/components/bots/BotMember.svelte b/frontend/app/src/components/bots/BotMember.svelte new file mode 100644 index 0000000000..aff488da2c --- /dev/null +++ b/frontend/app/src/components/bots/BotMember.svelte @@ -0,0 +1,179 @@ + + +{#if reviewMode !== undefined} + +{/if} + +
+ + + +
+
+

+ +

+
+
+ +
+
+ + + + + + + + + {#if canManage} + removeBot()}> + +
+ +
+
+ reviewPermissions()}> + +
+ +
+
+ {/if} + viewBotDetails()}> + +
+ +
+
+
+
+
+
+ + diff --git a/frontend/app/src/components/bots/BotSummary.svelte b/frontend/app/src/components/bots/BotSummary.svelte index 3d574743a0..f42475df97 100644 --- a/frontend/app/src/components/bots/BotSummary.svelte +++ b/frontend/app/src/components/bots/BotSummary.svelte @@ -4,9 +4,10 @@ emptySlashCommandPermissions, OpenChat, type BotMatch, - type CommunitySummary, type SlashCommandPermissions, hasEveryRequiredPermission, + type CommunityIdentifier, + type GroupChatIdentifier, } from "openchat-client"; import Avatar from "../Avatar.svelte"; import { getContext } from "svelte"; @@ -28,16 +29,38 @@ const client = getContext("client"); interface Props { + mode: "adding" | "editing" | "viewing"; bot: BotMatch; onClose: () => void; - community: CommunitySummary; + id: CommunityIdentifier | GroupChatIdentifier; + currentPermissions?: SlashCommandPermissions; } - let { bot, onClose, community }: Props = $props(); - let adding = $state(false); + let { bot, onClose, id, mode, currentPermissions }: Props = $props(); + let busy = $state(false); let requestedPermissions = $derived(flattenPermissions()); - let grantedPermissions = $state(flattenPermissions()); + let grantedPermissions = $state(currentPermissions ?? flattenPermissions()); let collapsed = $state(true); + let title = $derived.by(() => { + switch (mode) { + case "adding": + return i18nKey("bots.add.title"); + case "editing": + return i18nKey("bots.edit.title"); + case "viewing": + return i18nKey("bots.view.title"); + } + }); + let cta = $derived.by(() => { + switch (mode) { + case "adding": + return i18nKey("bots.add.addBot"); + case "editing": + return i18nKey("bots.edit.updateBot"); + case "viewing": + return i18nKey("bots.view.close"); + } + }); function flattenPermissions() { return bot.commands.reduce((p, c) => { @@ -61,9 +84,9 @@ } function addBot() { - adding = true; + busy = true; client - .addBotToCommunity(community.id, bot.id, $state.snapshot(grantedPermissions)) + .addBot(id, bot.id, $state.snapshot(grantedPermissions)) .then((success) => { if (!success) { toastStore.showFailureToast(i18nKey("bots.add.failure")); @@ -71,14 +94,41 @@ onClose(); } }) - .finally(() => (adding = false)); + .finally(() => (busy = false)); + } + + function updateBot() { + busy = true; + client + .updateBot(id, bot.id, $state.snapshot(grantedPermissions)) + .then((success) => { + if (!success) { + toastStore.showFailureToast(i18nKey("bots.edit.failure")); + } else { + onClose(); + } + }) + .finally(() => (busy = false)); + } + + function mainButton() { + switch (mode) { + case "adding": + addBot(); + break; + case "editing": + updateBot(); + break; + case "viewing": + onClose(); + } }
- +
@@ -117,82 +167,88 @@ {/each}
-
- -

- -

- - {#snippet chatTab()} - {#if requestedPermissions.chatPermissions.length === 0} - - {:else} - {#each requestedPermissions.chatPermissions as perm} - - togglePermission( - grantedPermissions, - "chatPermissions", + {#if mode !== "viewing"} +
+ +

+ +

+ + {#snippet chatTab()} + {#if requestedPermissions.chatPermissions.length === 0} + + {:else} + {#each requestedPermissions.chatPermissions as perm} + - - {/each} - {/if} - {/snippet} - {#snippet communityTab()} - {#if requestedPermissions.communityPermissions.length === 0} - - {:else} - {#each requestedPermissions.communityPermissions as perm} - - togglePermission( - grantedPermissions, - "communityPermissions", + on:change={() => + togglePermission( + grantedPermissions, + "chatPermissions", + perm, + )} + align={"start"}> + + {/each} + {/if} + {/snippet} + {#snippet communityTab()} + {#if requestedPermissions.communityPermissions.length === 0} + + {:else} + {#each requestedPermissions.communityPermissions as perm} + - - {/each} - {/if} - {/snippet} - {#snippet messageTab()} - {#if requestedPermissions.messagePermissions.length === 0} - - {:else} - {#each requestedPermissions.messagePermissions as perm} - - togglePermission( - grantedPermissions, - "messagePermissions", + on:change={() => + togglePermission( + grantedPermissions, + "communityPermissions", + perm, + )} + align={"start"}> + + {/each} + {/if} + {/snippet} + {#snippet messageTab()} + {#if requestedPermissions.messagePermissions.length === 0} + + {:else} + {#each requestedPermissions.messagePermissions as perm} + - - {/each} - {/if} - {/snippet} - -
+ on:change={() => + togglePermission( + grantedPermissions, + "messagePermissions", + perm, + )} + align={"start"}> +
+ {/each} + {/if} + {/snippet} +
+
+ {/if} diff --git a/frontend/app/src/components/home/BotChangedEvent.svelte b/frontend/app/src/components/home/BotChangedEvent.svelte new file mode 100644 index 0000000000..778f67ed17 --- /dev/null +++ b/frontend/app/src/components/home/BotChangedEvent.svelte @@ -0,0 +1,25 @@ + + + diff --git a/frontend/app/src/components/home/ChannelOrCommunityMembers.svelte b/frontend/app/src/components/home/ChannelOrCommunityMembers.svelte index 0460ae665b..bb691e0757 100644 --- a/frontend/app/src/components/home/ChannelOrCommunityMembers.svelte +++ b/frontend/app/src/components/home/ChannelOrCommunityMembers.svelte @@ -11,6 +11,7 @@ currentCommunityInvitedUsers as currentCommunityInvited, currentCommunityBlockedUsers as currentCommunityBlocked, currentCommunityLapsedMembers as currentCommunityLapsed, + currentCommunityBots, } from "openchat-client"; import { createEventDispatcher, getContext } from "svelte"; import { i18nKey } from "../../i18n/i18n"; @@ -110,6 +111,7 @@ members={[...$currentCommunityMembers.values()]} blocked={$currentCommunityBlocked} lapsed={$currentCommunityLapsed} + installedBots={$currentCommunityBots} on:close on:blockUser={onBlockCommunityUser} on:unblockUser={onUnblockCommunityUser} @@ -128,6 +130,7 @@ members={$currentChatMembers} blocked={$currentChatBlocked} lapsed={$currentChatLapsed} + installedBots={$currentCommunityBots} on:close on:blockUser={onBlockGroupUser} on:unblockUser={onUnblockGroupUser} diff --git a/frontend/app/src/components/home/ChatEvent.svelte b/frontend/app/src/components/home/ChatEvent.svelte index 8ec2c78642..94d69519bb 100644 --- a/frontend/app/src/components/home/ChatEvent.svelte +++ b/frontend/app/src/components/home/ChatEvent.svelte @@ -31,6 +31,7 @@ import ChatUnfrozenEvent from "./ChatUnfrozenEvent.svelte"; import page from "page"; import { i18nKey, interpolate } from "../../i18n/i18n"; + import BotChangedEvent from "./BotChangedEvent.svelte"; const client = getContext("client"); const dispatch = createEventDispatcher(); @@ -303,6 +304,27 @@ {:else if event.event.kind === "chat_unfrozen"} +{:else if event.event.kind === "bot_added"} + +{:else if event.event.kind === "bot_removed"} + +{:else if event.event.kind === "bot_updated"} + {:else if !client.isEventKindHidden(event.event.kind)} -
Unexpected event type
+
Unexpected event type: {event.event.kind}
{/if} diff --git a/frontend/app/src/components/home/RightPanel.svelte b/frontend/app/src/components/home/RightPanel.svelte index 67207778d0..f639bbe201 100644 --- a/frontend/app/src/components/home/RightPanel.svelte +++ b/frontend/app/src/components/home/RightPanel.svelte @@ -53,6 +53,8 @@ currentCommunityLapsedMembers as currentCommunityLapsed, selectedCommunity, eventsStore, + currentCommunityBots, + currentChatBots, } from "openchat-client"; const dispatch = createEventDispatcher(); @@ -467,6 +469,7 @@ blocked={$currentCommunityBlocked} lapsed={$currentCommunityLapsed} initialUsergroup={lastState.userGroupId} + installedBots={$currentCommunityBots} on:close={popRightPanelHistory} on:blockUser={onBlockCommunityUser} on:unblockUser={onUnblockCommnityUser} @@ -509,6 +512,7 @@ members={$currentChatMembers} blocked={$currentChatBlocked} lapsed={$currentChatLapsedMembers} + installedBots={$currentChatBots} on:close={popRightPanelHistory} on:blockUser={onBlockGroupUser} on:unblockUser={onUnblockGroupUser} diff --git a/frontend/app/src/components/home/groupdetails/Members.svelte b/frontend/app/src/components/home/groupdetails/Members.svelte index 178234eece..24fec967cc 100644 --- a/frontend/app/src/components/home/groupdetails/Members.svelte +++ b/frontend/app/src/components/home/groupdetails/Members.svelte @@ -23,7 +23,9 @@ LARGE_GROUP_THRESHOLD, userStore, currentUser as user, - selectedCommunity, + type ExternalBot, + externalBots, + type SlashCommandPermissions, } from "openchat-client"; import { createEventDispatcher, getContext } from "svelte"; import InvitedUser from "./InvitedUser.svelte"; @@ -35,6 +37,9 @@ import User from "./User.svelte"; import { botsEnabled } from "../../../utils/bots"; import BotExplorer from "../../bots/BotExplorer.svelte"; + import BotMember from "../../bots/BotMember.svelte"; + + type EnhancedExternalBot = ExternalBot & { grantedPermissions: SlashCommandPermissions }; const MAX_SEARCH_RESULTS = 255; // irritatingly this is a nat8 in the candid const client = getContext("client"); @@ -45,6 +50,7 @@ export let members: MemberType[]; export let blocked: Set; export let lapsed: Set; + export let installedBots: Map; export let initialUsergroup: number | undefined = undefined; export let showHeader = true; @@ -65,6 +71,30 @@ $: showLapsed = lapsedMembers.length > 0; $: canInvite = client.canInviteUsers(collection.id); $: canPromoteMyselfToOwner = false; + $: bots = hydrateBots(installedBots, $externalBots).filter((b) => + matchesSearch(searchTermLower, b), + ); + $: canManageBots = client.canManageBots(collection.id); + $: botContainer = + collection.kind === "channel" + ? ({ kind: "community", communityId: collection.id.communityId } as CommunityIdentifier) + : collection.id; + + function hydrateBots( + bots: Map, + allBots: Map, + ): EnhancedExternalBot[] { + return [...bots.entries()].reduce((bots, [id, perm]) => { + const bot = allBots.get(id); + if (bot !== undefined) { + bots.push({ + ...bot, + grantedPermissions: perm, + }); + } + return bots; + }, [] as EnhancedExternalBot[]); + } function matchingUsers( term: string, @@ -130,8 +160,16 @@ dispatch("showInviteUsers"); } - function matchesSearch(searchTermLower: string, user: UserSummary): boolean { + function matchesSearch(searchTermLower: string, user: UserSummary | ExternalBot): boolean { if (searchTermLower === "") return true; + if (user.kind === "external_bot") { + return ( + user.name.toLowerCase().includes(searchTermLower) || + (user.description !== undefined && + user.description.toLocaleLowerCase().includes(searchTermLower)) + ); + } + if (user.username === undefined) return true; return ( user.username.toLowerCase().includes(searchTermLower) || @@ -196,7 +234,7 @@ on:showInviteUsers={showInviteUsers} /> {/if} -{#if collection.level === "community"} +{#if collection.kind !== "channel"}
- + {#if collection.kind === "community"} + + {/if} {#if botsEnabled}
-{:else if selectedTab === "add-bots" && collection.kind === "community" && $selectedCommunity} +{:else if selectedTab === "add-bots" && collection.kind !== "channel"}
- +
{/if} @@ -415,4 +476,11 @@ } } } + + .member_type_label { + padding: $sp2 $sp4; + text-transform: uppercase; + @include font(light, normal, fs-50); + border-bottom: 1px solid var(--bd); + } diff --git a/frontend/app/src/i18n/ar.json b/frontend/app/src/i18n/ar.json index 55739d5282..ef179f417a 100644 --- a/frontend/app/src/i18n/ar.json +++ b/frontend/app/src/i18n/ar.json @@ -244,6 +244,16 @@ "diamond": { "desc": "انشر رابطًا لشرح العضوية الماسية" }, + "edit": { + "failure": "نأسف لعدم تمكننا من تحديث أذونات الروبوت", + "title": "تحديث أذونات الروبوت", + "updateBot": "تحديث البوت" + }, + "events": { + "add": "تم إضافة الروبوت **{botname}** بواسطة {username}", + "remove": "تم إزالة الروبوت **{botname}** بواسطة {username}", + "update": "تم تحديث الروبوت **{botname}** بواسطة {username}" + }, "explorer": { "addBots": "إضافة الروبوتات", "loadMore": "تحميل المزيد..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "إزالة البوت", + "removeFailed": "نأسف لأننا لم نتمكن من إزالة الروبوت", + "review": "مراجعة أذونات الروبوت", + "view": "عرض تفاصيل البوت" + }, "matchingCommands": "أوامر المطابقة", + "member": { + "bots": "الروبوتات", + "people": "الناس" + }, "poll": { "desc": "إنشاء استطلاع رأي في الدردشة الحالية" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "ابدأ اقتراحًا لتحديث روبوت OpenChat الحالي" }, + "view": { + "close": "يغلق", + "title": "تفاصيل البوت" + }, "witch": { "desc": "استدعاء الساحرة" } diff --git a/frontend/app/src/i18n/cn.json b/frontend/app/src/i18n/cn.json index a2a33fe6d2..9fbf266295 100644 --- a/frontend/app/src/i18n/cn.json +++ b/frontend/app/src/i18n/cn.json @@ -244,6 +244,16 @@ "diamond": { "desc": "发布链接解释钻石会员资格" }, + "edit": { + "failure": "抱歉,我们无法更新机器人权限", + "title": "更新机器人权限", + "updateBot": "更新机器人" + }, + "events": { + "add": "机器人 **{botname}** 由 {username} 添加", + "remove": "机器人 **{botname}** 已被 {username} 移除", + "update": "机器人 **{botname}** 由 {username} 更新" + }, "explorer": { "addBots": "添加机器人", "loadMore": "加载更多..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "移除机器人", + "removeFailed": "抱歉,我们无法移除该机器人", + "review": "审查机器人权限", + "view": "查看机器人详细信息" + }, "matchingCommands": "匹配命令", + "member": { + "bots": "机器人", + "people": "人们" + }, "poll": { "desc": "在当前聊天中创建投票" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "发起更新现有 OpenChat 机器人的提案" }, + "view": { + "close": "关闭", + "title": "机器人详细信息" + }, "witch": { "desc": "召唤女巫" } diff --git a/frontend/app/src/i18n/de.json b/frontend/app/src/i18n/de.json index 808cbe9f32..d05757820c 100644 --- a/frontend/app/src/i18n/de.json +++ b/frontend/app/src/i18n/de.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Posten Sie einen Link, um die Diamond-Mitgliedschaft zu erklären" }, + "edit": { + "failure": "Leider konnten wir die Bot-Berechtigungen nicht aktualisieren", + "title": "Bot-Berechtigungen aktualisieren", + "updateBot": "Bot aktualisieren" + }, + "events": { + "add": "Bot **{botname}** hinzugefügt von {username}", + "remove": "Bot **{botname}** von {username} entfernt", + "update": "Bot **{botname}** aktualisiert von {username}" + }, "explorer": { "addBots": "Bots hinzufügen", "loadMore": "Mehr laden..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Bot entfernen", + "removeFailed": "Es ist uns leider nicht gelungen, den Bot zu entfernen.", + "review": "Überprüfen Sie die Bot-Berechtigungen", + "view": "Botdetails anzeigen" + }, "matchingCommands": "Passende Befehle", + "member": { + "bots": "Bots", + "people": "Menschen" + }, "poll": { "desc": "Erstellen Sie eine Umfrage im aktuellen Chat" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Starten Sie einen Vorschlag zur Aktualisierung eines vorhandenen OpenChat-Bots" }, + "view": { + "close": "Schließen", + "title": "Bot-Details" + }, "witch": { "desc": "Beschwöre die Hexe" } diff --git a/frontend/app/src/i18n/en.json b/frontend/app/src/i18n/en.json index 4180f9bb98..c2689844f9 100644 --- a/frontend/app/src/i18n/en.json +++ b/frontend/app/src/i18n/en.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Post a link to explain Diamond membership" }, + "edit": { + "failure": "Sorry we were unable to update the bot permissions", + "title": "Update bot permissions", + "updateBot": "Update bot" + }, + "events": { + "add": "Bot **{botname}** added by {username}", + "remove": "Bot **{botname}** removed by {username}", + "update": "Bot **{botname}** updated by {username}" + }, "explorer": { "addBots": "Add bots", "loadMore": "Load more..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Remove bot", + "removeFailed": "Sorry we were unable to remove the bot", + "review": "Review bot permissions", + "view": "View bot details" + }, "matchingCommands": "Matching commands", + "member": { + "bots": "Bots", + "people": "People" + }, "poll": { "desc": "Create a poll in the current chat" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Start a proposal to update an existing OpenChat bot" }, + "view": { + "close": "Close", + "title": "Bot details" + }, "witch": { "desc": "Summon the witch" } diff --git a/frontend/app/src/i18n/es.json b/frontend/app/src/i18n/es.json index fc390a743c..d76cb81104 100644 --- a/frontend/app/src/i18n/es.json +++ b/frontend/app/src/i18n/es.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Publica un enlace para explicar la membresía Diamante" }, + "edit": { + "failure": "Lo sentimos, no pudimos actualizar los permisos del bot.", + "title": "Actualizar permisos de bot", + "updateBot": "Actualizar bot" + }, + "events": { + "add": "Bot **{botname}** añadido por {username}", + "remove": "Bot **{botname}** eliminado por {username}", + "update": "Bot **{botname}** actualizado por {username}" + }, "explorer": { "addBots": "Agregar bots", "loadMore": "Cargar más..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Eliminar bot", + "removeFailed": "Lo sentimos, no pudimos eliminar el bot.", + "review": "Revisar los permisos del bot", + "view": "Ver detalles del bot" + }, "matchingCommands": "Comandos coincidentes", + "member": { + "bots": "Bots", + "people": "Gente" + }, "poll": { "desc": "Crear una encuesta en el chat actual" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Iniciar una propuesta para actualizar un bot de OpenChat existente" }, + "view": { + "close": "Cerca", + "title": "Detalles del bot" + }, "witch": { "desc": "Invocar a la bruja" } diff --git a/frontend/app/src/i18n/fa.json b/frontend/app/src/i18n/fa.json index 5c622e2af8..44719ef1fa 100644 --- a/frontend/app/src/i18n/fa.json +++ b/frontend/app/src/i18n/fa.json @@ -244,6 +244,16 @@ "diamond": { "desc": "یک لینک برای توضیح عضویت در Diamond ارسال کنید" }, + "edit": { + "failure": "متأسفیم که نتوانستیم مجوزهای ربات را به روز کنیم", + "title": "به روز رسانی مجوزهای ربات", + "updateBot": "به روز رسانی ربات" + }, + "events": { + "add": "ربات **{botname}** اضافه شده توسط {username}", + "remove": "ربات **{botname}** توسط {username} حذف شد", + "update": "ربات **{botname}** به روز شده توسط {username}" + }, "explorer": { "addBots": "ربات ها را اضافه کنید", "loadMore": "بارگیری بیشتر..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "حذف ربات", + "removeFailed": "متأسفیم که نتوانستیم ربات را حذف کنیم", + "review": "مجوزهای ربات را بررسی کنید", + "view": "مشاهده جزئیات ربات" + }, "matchingCommands": "تطبیق دستورات", + "member": { + "bots": "ربات ها", + "people": "مردم" + }, "poll": { "desc": "یک نظرسنجی در چت فعلی ایجاد کنید" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "پیشنهادی را برای به روز رسانی ربات OpenChat موجود شروع کنید" }, + "view": { + "close": "بستن", + "title": "جزئیات ربات" + }, "witch": { "desc": "جادوگر را احضار کن" } diff --git a/frontend/app/src/i18n/fr.json b/frontend/app/src/i18n/fr.json index 4f2813f881..d42dce1e9c 100644 --- a/frontend/app/src/i18n/fr.json +++ b/frontend/app/src/i18n/fr.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Postez un lien pour expliquer l'adhésion Diamond" }, + "edit": { + "failure": "Désolé, nous n'avons pas pu mettre à jour les autorisations du bot", + "title": "Mettre à jour les autorisations du bot", + "updateBot": "Bot de mise à jour" + }, + "events": { + "add": "Bot **{botname}** ajouté par {username}", + "remove": "Bot **{botname}** supprimé par {username}", + "update": "Bot **{botname}** mis à jour par {username}" + }, "explorer": { "addBots": "Ajouter des robots", "loadMore": "Charger plus..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Supprimer le bot", + "removeFailed": "Désolé, nous n'avons pas pu supprimer le bot", + "review": "Examiner les autorisations du robot", + "view": "Afficher les détails du bot" + }, "matchingCommands": "Commandes correspondantes", + "member": { + "bots": "Les robots", + "people": "Personnes" + }, "poll": { "desc": "Créer un sondage dans le chat actuel" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Démarrer une proposition pour mettre à jour un bot OpenChat existant" }, + "view": { + "close": "Fermer", + "title": "Détails du bot" + }, "witch": { "desc": "Invoquer la sorcière" } diff --git a/frontend/app/src/i18n/hi.json b/frontend/app/src/i18n/hi.json index a181181be0..319c6fb3e2 100644 --- a/frontend/app/src/i18n/hi.json +++ b/frontend/app/src/i18n/hi.json @@ -244,6 +244,16 @@ "diamond": { "desc": "डायमंड सदस्यता के बारे में बताने के लिए लिंक पोस्ट करें" }, + "edit": { + "failure": "क्षमा करें, हम बॉट अनुमतियों को अपडेट करने में असमर्थ थे", + "title": "बॉट अनुमतियाँ अपडेट करें", + "updateBot": "बॉट अपडेट करें" + }, + "events": { + "add": "बॉट **{botname}** को {username} द्वारा जोड़ा गया", + "remove": "बॉट **{botname}** को {username} द्वारा हटा दिया गया", + "update": "बॉट **{botname}** को {username} द्वारा अपडेट किया गया" + }, "explorer": { "addBots": "बॉट जोड़ें", "loadMore": "और लोड करें..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "बॉट हटाएँ", + "removeFailed": "खेद है कि हम बॉट को हटाने में असमर्थ रहे", + "review": "बॉट अनुमतियों की समीक्षा करें", + "view": "बॉट विवरण देखें" + }, "matchingCommands": "मिलान आदेश", + "member": { + "bots": "बॉट", + "people": "लोग" + }, "poll": { "desc": "वर्तमान चैट में पोल बनाएँ" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "मौजूदा OpenChat बॉट को अपडेट करने के लिए प्रस्ताव शुरू करें" }, + "view": { + "close": "बंद करना", + "title": "बॉट विवरण" + }, "witch": { "desc": "चुड़ैल को बुलाओ" } diff --git a/frontend/app/src/i18n/it.json b/frontend/app/src/i18n/it.json index db2055cac4..00e6187a40 100644 --- a/frontend/app/src/i18n/it.json +++ b/frontend/app/src/i18n/it.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Pubblica un link per spiegare l'appartenenza a Diamond" }, + "edit": { + "failure": "Spiacenti, non siamo riusciti ad aggiornare le autorizzazioni del bot", + "title": "Aggiorna i permessi del bot", + "updateBot": "Aggiorna bot" + }, + "events": { + "add": "Bot **{botname}** aggiunto da {username}", + "remove": "Bot **{botname}** rimosso da {username}", + "update": "Bot **{botname}** aggiornato da {username}" + }, "explorer": { "addBots": "Aggiungi bot", "loadMore": "Carica altro..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Rimuovi bot", + "removeFailed": "Spiacenti, non siamo riusciti a rimuovere il bot", + "review": "Rivedi le autorizzazioni del bot", + "view": "Visualizza i dettagli del bot" + }, "matchingCommands": "Comandi corrispondenti", + "member": { + "bots": "I bot", + "people": "Persone" + }, "poll": { "desc": "Crea un sondaggio nella chat corrente" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Avvia una proposta per aggiornare un bot OpenChat esistente" }, + "view": { + "close": "Vicino", + "title": "Dettagli del bot" + }, "witch": { "desc": "Evoca la strega" } diff --git a/frontend/app/src/i18n/iw.json b/frontend/app/src/i18n/iw.json index 8a3e5da289..1c1a8f322e 100644 --- a/frontend/app/src/i18n/iw.json +++ b/frontend/app/src/i18n/iw.json @@ -244,6 +244,16 @@ "diamond": { "desc": "פרסם קישור להסבר על חברות Diamond" }, + "edit": { + "failure": "מצטערים שלא הצלחנו לעדכן את הרשאות הבוט", + "title": "עדכן הרשאות בוט", + "updateBot": "עדכן את הבוט" + }, + "events": { + "add": "בוט **{botname}** נוסף על ידי {username}", + "remove": "הבוט **{botname}** הוסר על ידי {username}", + "update": "בוט **{botname}** עודכן על ידי {username}" + }, "explorer": { "addBots": "הוסף בוטים", "loadMore": "טען עוד..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "הסר בוט", + "removeFailed": "מצטערים שלא הצלחנו להסיר את הבוט", + "review": "בדוק את הרשאות הבוט", + "view": "הצג את פרטי הבוט" + }, "matchingCommands": "התאמת פקודות", + "member": { + "bots": "בוטים", + "people": "אֲנָשִׁים" + }, "poll": { "desc": "צור סקר בצ'אט הנוכחי" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "התחל הצעה לעדכון בוט OpenChat קיים" }, + "view": { + "close": "לִסְגוֹר", + "title": "פרטי בוט" + }, "witch": { "desc": "לזמן את המכשפה" } diff --git a/frontend/app/src/i18n/jp.json b/frontend/app/src/i18n/jp.json index 6de48bb6dd..1d6ed661be 100644 --- a/frontend/app/src/i18n/jp.json +++ b/frontend/app/src/i18n/jp.json @@ -244,6 +244,16 @@ "diamond": { "desc": "ダイヤモンド会員資格を説明するリンクを投稿する" }, + "edit": { + "failure": "申し訳ありませんが、ボットの権限を更新できませんでした", + "title": "ボットの権限を更新する", + "updateBot": "ボットの更新" + }, + "events": { + "add": "ボット **{botname}** が {username} によって追加されました", + "remove": "ボット **{botname}** は {username} によって削除されました", + "update": "ボット **{botname}** が {username} によって更新されました" + }, "explorer": { "addBots": "ボットを追加", "loadMore": "さらに読み込む..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "ボットを削除", + "removeFailed": "申し訳ありませんが、ボットを削除できませんでした", + "review": "ボットの権限を確認する", + "view": "ボットの詳細を表示" + }, "matchingCommands": "一致するコマンド", + "member": { + "bots": "ボット", + "people": "人々" + }, "poll": { "desc": "現在のチャットでアンケートを作成する" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "既存のOpenChatボットを更新する提案を開始する" }, + "view": { + "close": "近い", + "title": "ボットの詳細" + }, "witch": { "desc": "魔女を召喚する" } diff --git a/frontend/app/src/i18n/pl.json b/frontend/app/src/i18n/pl.json index 379f99564e..9cd25a193c 100644 --- a/frontend/app/src/i18n/pl.json +++ b/frontend/app/src/i18n/pl.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Opublikuj link wyjaśniający członkostwo Diamond" }, + "edit": { + "failure": "Przepraszamy, nie udało nam się zaktualizować uprawnień bota", + "title": "Zaktualizuj uprawnienia bota", + "updateBot": "Aktualizacja bota" + }, + "events": { + "add": "Bot **{botname}** dodany przez {username}", + "remove": "Bot **{botname}** został usunięty przez {username}", + "update": "Bot **{botname}** zaktualizowany przez {username}" + }, "explorer": { "addBots": "Dodaj boty", "loadMore": "Załaduj więcej..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Usuń bota", + "removeFailed": "Przepraszamy, nie udało nam się usunąć bota", + "review": "Przejrzyj uprawnienia bota", + "view": "Wyświetl szczegóły bota" + }, "matchingCommands": "Dopasowywanie poleceń", + "member": { + "bots": "Boty", + "people": "Ludzie" + }, "poll": { "desc": "Utwórz ankietę w bieżącym czacie" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Rozpocznij propozycję aktualizacji istniejącego bota OpenChat" }, + "view": { + "close": "Zamknąć", + "title": "Szczegóły bota" + }, "witch": { "desc": "Przywołaj czarownicę" } diff --git a/frontend/app/src/i18n/ru.json b/frontend/app/src/i18n/ru.json index 91659d32d9..709488f85e 100644 --- a/frontend/app/src/i18n/ru.json +++ b/frontend/app/src/i18n/ru.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Опубликуйте ссылку, чтобы объяснить суть членства Diamond" }, + "edit": { + "failure": "Извините, нам не удалось обновить разрешения бота.", + "title": "Обновить разрешения бота", + "updateBot": "Обновление бота" + }, + "events": { + "add": "Бот **{botname}** добавлен {username}", + "remove": "Бот **{botname}** удален пользователем {username}", + "update": "Бот **{botname}** обновлен {username}" + }, "explorer": { "addBots": "Добавить ботов", "loadMore": "Загрузить еще..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Удалить бота", + "removeFailed": "Извините, мы не смогли удалить бота.", + "review": "Просмотр разрешений бота", + "view": "Посмотреть подробности бота" + }, "matchingCommands": "Соответствующие команды", + "member": { + "bots": "Боты", + "people": "Люди" + }, "poll": { "desc": "Создать опрос в текущем чате" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Начать предложение по обновлению существующего бота OpenChat" }, + "view": { + "close": "Закрывать", + "title": "Подробности бота" + }, "witch": { "desc": "Вызов ведьмы" } diff --git a/frontend/app/src/i18n/uk.json b/frontend/app/src/i18n/uk.json index 71d35e5a09..6c560e38f1 100644 --- a/frontend/app/src/i18n/uk.json +++ b/frontend/app/src/i18n/uk.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Опублікуйте посилання, щоб пояснити Діамантове членство" }, + "edit": { + "failure": "На жаль, ми не змогли оновити дозволи бота", + "title": "Оновіть дозволи бота", + "updateBot": "Оновлення бота" + }, + "events": { + "add": "Бот **{botname}** додав {username}", + "remove": "Бот **{botname}** видалено {username}", + "update": "Бот **{botname}** оновлено {username}" + }, "explorer": { "addBots": "Додайте ботів", "loadMore": "Завантажити більше..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Видалити бота", + "removeFailed": "На жаль, ми не змогли видалити бота", + "review": "Перегляньте дозволи бота", + "view": "Переглянути деталі бота" + }, "matchingCommands": "Зіставлення команд", + "member": { + "bots": "Боти", + "people": "Люди" + }, "poll": { "desc": "Створити опитування в поточному чаті" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Розпочніть пропозицію щодо оновлення існуючого бота OpenChat" }, + "view": { + "close": "Закрити", + "title": "Деталі бота" + }, "witch": { "desc": "Викликати відьму" } diff --git a/frontend/app/src/i18n/vi.json b/frontend/app/src/i18n/vi.json index bf202ad2e9..4b3429c8be 100644 --- a/frontend/app/src/i18n/vi.json +++ b/frontend/app/src/i18n/vi.json @@ -244,6 +244,16 @@ "diamond": { "desc": "Đăng liên kết để giải thích về tư cách thành viên Kim cương" }, + "edit": { + "failure": "Xin lỗi, chúng tôi không thể cập nhật quyền của bot", + "title": "Cập nhật quyền bot", + "updateBot": "Cập nhật bot" + }, + "events": { + "add": "Bot **{botname}** được thêm vào bởi {username}", + "remove": "Bot **{botname}** đã bị xóa bởi {username}", + "update": "Bot **{botname}** được cập nhật bởi {username}" + }, "explorer": { "addBots": "Thêm bot", "loadMore": "Tải thêm..." @@ -287,7 +297,17 @@ } } }, + "manage": { + "remove": "Xóa bot", + "removeFailed": "Xin lỗi chúng tôi không thể xóa bot", + "review": "Xem lại quyền của bot", + "view": "Xem chi tiết bot" + }, "matchingCommands": "Lệnh khớp", + "member": { + "bots": "Bots", + "people": "Mọi người" + }, "poll": { "desc": "Tạo một cuộc thăm dò trong cuộc trò chuyện hiện tại" }, @@ -307,6 +327,10 @@ "update_bot": { "desc": "Bắt đầu đề xuất cập nhật bot OpenChat hiện có" }, + "view": { + "close": "Đóng", + "title": "Chi tiết bot" + }, "witch": { "desc": "Triệu hồi phù thủy" } diff --git a/frontend/openchat-agent/src/services/common/chatMappersV2.ts b/frontend/openchat-agent/src/services/common/chatMappersV2.ts index 5025f061ba..7d32a0ee95 100644 --- a/frontend/openchat-agent/src/services/common/chatMappersV2.ts +++ b/frontend/openchat-agent/src/services/common/chatMappersV2.ts @@ -120,6 +120,7 @@ import type { SetPinNumberResponse, MessagePermission, SlashCommandPermissions, + BotGroupDetails, } from "openchat-shared"; import { ProposalDecisionStatus, @@ -284,6 +285,13 @@ import type { CommunityPermission, MessagePermission as ApiMessagePermission, SlashCommandPermissions as ApiSlashCommandPermissions, + CommunityRemoveBotResponse, + CommunityAddBotResponse, + CommunityUpdateBotResponse, + GroupRemoveBotResponse, + GroupAddBotResponse, + GroupUpdateBotResponse, + BotGroupDetails as ApiBotGroupDetails, } from "../../typebox"; const E8S_AS_BIGINT = BigInt(100_000_000); @@ -2607,6 +2615,7 @@ export function groupDetailsResponse( }); } } + const bots = "bots" in value.Success ? value.Success.bots : []; return { members, blockedUsers: new Set(value.Success.blocked_users.map(principalBytesToString)), @@ -2614,6 +2623,7 @@ export function groupDetailsResponse( pinnedMessages: new Set(value.Success.pinned_messages), rules: value.Success.chat_rules, timestamp: value.Success.timestamp, + bots: bots.map(botGroupDetails), }; } throw new UnsupportedValueError("Unexpected ApiDeleteMessageResponse type received", value); @@ -2642,6 +2652,8 @@ export function groupDetailsUpdatesResponse( (invited_users) => new Set(invited_users.map(principalBytesToString)), ), timestamp: value.Success.timestamp, + botsAddedOrUpdated: value.Success.bots_added_or_updated.map(botGroupDetails), + botsRemoved: new Set(value.Success.bots_removed.map(principalBytesToString)), }; } else if ("SuccessNoUpdates" in value) { return { @@ -3316,3 +3328,38 @@ export function slashCommandPermissions( messagePermissions: value.message.map(messagePermission), }; } + +export function removeBotResponse( + value: CommunityRemoveBotResponse | GroupRemoveBotResponse, +): boolean { + if (value === "Success") { + return true; + } + console.warn("Community|GroupRemoveBotResponse failed with ", value); + return false; +} + +export function addBotResponse(value: CommunityAddBotResponse | GroupAddBotResponse): boolean { + if (value === "Success" || value === "AlreadyAdded") { + return true; + } + console.warn("Community|GroupAddBotResponse failed with ", value); + return false; +} + +export function updateBotResponse( + value: CommunityUpdateBotResponse | GroupUpdateBotResponse, +): boolean { + if (value === "Success") { + return true; + } + console.warn("Community|GroupUpdateBotResponse failed with ", value); + return false; +} + +export function botGroupDetails(value: ApiBotGroupDetails): BotGroupDetails { + return { + id: principalBytesToString(value.user_id), + permissions: slashCommandPermissions(value.permissions), + }; +} diff --git a/frontend/openchat-agent/src/services/community/community.client.ts b/frontend/openchat-agent/src/services/community/community.client.ts index 144c3856e0..a782e8e2be 100644 --- a/frontend/openchat-agent/src/services/community/community.client.ts +++ b/frontend/openchat-agent/src/services/community/community.client.ts @@ -10,7 +10,6 @@ import { } from "../../utils/mapping"; import type { AgentConfig } from "../../config"; import { - addBotResponse, addMembersToChannelResponse, apiCommunityRole, apiMemberRole, @@ -25,7 +24,6 @@ import { exploreChannelsResponse, followThreadResponse, importGroupResponse, - removeBotResponse, removeMemberFromChannelResponse, removeMemberResponse, reportMessageResponse, @@ -75,6 +73,9 @@ import { apiChatPermission, apiCommunityPermission, apiMessagePermission, + addBotResponse, + updateBotResponse, + removeBotResponse, } from "../common/chatMappersV2"; import type { AddMembersToChannelResponse, @@ -295,6 +296,8 @@ import { CommunityAddBotResponse, CommunityRemoveBotArgs, CommunityRemoveBotResponse, + CommunityUpdateBotArgs, + CommunityUpdateBotResponse, } from "../../typebox"; export class CommunityClient extends CandidService { @@ -1738,9 +1741,27 @@ export class CommunityClient extends CandidService { ); } + updateBot(botId: string, grantedPermissions: SlashCommandPermissions): Promise { + return this.executeMsgpackUpdate( + "update_bot", + { + bot_id: principalStringToBytes(botId), + granted_permissions: { + chat: grantedPermissions.chatPermissions.map(apiChatPermission), + community: grantedPermissions.communityPermissions.map(apiCommunityPermission), + message: grantedPermissions.messagePermissions.map(apiMessagePermission), + thread: grantedPermissions.messagePermissions.map(apiMessagePermission), + }, + }, + updateBotResponse, + CommunityUpdateBotArgs, + CommunityUpdateBotResponse, + ); + } + removeBot(botId: string): Promise { return this.executeMsgpackUpdate( - "add_bot", + "remove_bot", { bot_id: principalStringToBytes(botId), }, diff --git a/frontend/openchat-agent/src/services/community/mappersV2.ts b/frontend/openchat-agent/src/services/community/mappersV2.ts index 8426abc50b..a3070feb42 100644 --- a/frontend/openchat-agent/src/services/community/mappersV2.ts +++ b/frontend/openchat-agent/src/services/community/mappersV2.ts @@ -1,7 +1,6 @@ import type { AddMembersToChannelResponse, BlockCommunityUserResponse, - BotGroupDetails, ChangeCommunityRoleResponse, ChannelMatch, ChannelSummaryResponse, @@ -65,14 +64,12 @@ import type { CommunitySetMemberDisplayNameResponse, CommunityDeleteUserGroupsResponse, CommunityUpdateUserGroupResponse, - CommunityAddBotResponse, - CommunityRemoveBotResponse, - BotGroupDetails as ApiBotGroupDetails, } from "../../typebox"; import { mapOptional, optionUpdateV2, principalBytesToString } from "../../utils/mapping"; import { accessGateConfig, apiCommunityPermissionRole, + botGroupDetails, chatMetrics, communityChannelSummary, communityPermissions, @@ -82,7 +79,6 @@ import { memberRole, mentions, messageEvent, - slashCommandPermissions, threadSyncDetails, updatedEvent, userGroup, @@ -90,22 +86,6 @@ import { import { identity } from "../../utils/mapping"; import { mapCommonResponses } from "../common/commonResponseMapper"; -export function removeBotResponse(value: CommunityRemoveBotResponse): boolean { - if (value === "Success") { - return true; - } - console.warn("CommunityRemoveBotResponse failed with ", value); - return false; -} - -export function addBotResponse(value: CommunityAddBotResponse): boolean { - if (value === "Success" || value === "AlreadyAdded") { - return true; - } - console.warn("CommunityAddBotResponse failed with ", value); - return false; -} - export function addMembersToChannelResponse( value: CommunityAddMembersToChannelResponse, ): AddMembersToChannelResponse { @@ -496,13 +476,6 @@ export function communityDetailsResponse( } } -export function botGroupDetails(value: ApiBotGroupDetails): BotGroupDetails { - return { - id: principalBytesToString(value.user_id), - permissions: slashCommandPermissions(value.permissions), - }; -} - export function userGroupDetails(value: TUserGroupDetails): [number, UserGroupDetails] { return [ value.user_group_id, diff --git a/frontend/openchat-agent/src/services/group/group.client.ts b/frontend/openchat-agent/src/services/group/group.client.ts index df254292ef..4835a0a83f 100644 --- a/frontend/openchat-agent/src/services/group/group.client.ts +++ b/frontend/openchat-agent/src/services/group/group.client.ts @@ -50,6 +50,7 @@ import type { VideoCallPresence, VideoCallParticipantsResponse, AccessGateConfig, + SlashCommandPermissions, } from "openchat-shared"; import { DestinationInvalidError, @@ -91,9 +92,13 @@ import { } from "../../utils/caching"; import { acceptP2PSwapResponse, + addBotResponse, addRemoveReactionResponse, apiAccessGateConfig, + apiChatPermission, + apiCommunityPermission, apiMessageContent, + apiMessagePermission, apiUser as apiUserV2, apiVideoCallPresence, cancelP2PSwapResponse, @@ -112,11 +117,13 @@ import { pinMessageResponse, registerPollVoteResponse, registerProposalVoteResponse, + removeBotResponse, searchGroupChatResponse, setVideoCallPresence, threadPreviewsResponse, undeleteMessageResponse, unpinMessageResponse, + updateBotResponse, updateGroupResponse, videoCallParticipantsResponse, } from "../common/chatMappersV2"; @@ -222,6 +229,12 @@ import { GroupUpdateGroupResponse, GroupVideoCallParticipantsArgs, GroupVideoCallParticipantsResponse, + GroupAddBotArgs, + GroupAddBotResponse, + GroupUpdateBotArgs, + GroupUpdateBotResponse, + GroupRemoveBotArgs, + GroupRemoveBotResponse, } from "../../typebox"; export class GroupClient extends CandidService { @@ -1277,4 +1290,52 @@ export class GroupClient extends CandidService { GroupCancelInvitesResponse, ); } + + addBot(botId: string, grantedPermissions: SlashCommandPermissions): Promise { + return this.executeMsgpackUpdate( + "add_bot", + { + bot_id: principalStringToBytes(botId), + granted_permissions: { + chat: grantedPermissions.chatPermissions.map(apiChatPermission), + community: grantedPermissions.communityPermissions.map(apiCommunityPermission), + message: grantedPermissions.messagePermissions.map(apiMessagePermission), + thread: grantedPermissions.messagePermissions.map(apiMessagePermission), + }, + }, + addBotResponse, + GroupAddBotArgs, + GroupAddBotResponse, + ); + } + + updateBot(botId: string, grantedPermissions: SlashCommandPermissions): Promise { + return this.executeMsgpackUpdate( + "update_bot", + { + bot_id: principalStringToBytes(botId), + granted_permissions: { + chat: grantedPermissions.chatPermissions.map(apiChatPermission), + community: grantedPermissions.communityPermissions.map(apiCommunityPermission), + message: grantedPermissions.messagePermissions.map(apiMessagePermission), + thread: grantedPermissions.messagePermissions.map(apiMessagePermission), + }, + }, + updateBotResponse, + GroupUpdateBotArgs, + GroupUpdateBotResponse, + ); + } + + removeBot(botId: string): Promise { + return this.executeMsgpackUpdate( + "remove_bot", + { + bot_id: principalStringToBytes(botId), + }, + removeBotResponse, + GroupRemoveBotArgs, + GroupRemoveBotResponse, + ); + } } diff --git a/frontend/openchat-agent/src/services/openchatAgent.ts b/frontend/openchat-agent/src/services/openchatAgent.ts index 47d092046b..ecab0ef0cb 100644 --- a/frontend/openchat-agent/src/services/openchatAgent.ts +++ b/frontend/openchat-agent/src/services/openchatAgent.ts @@ -4019,16 +4019,39 @@ export class OpenChatAgent extends EventTarget { return this._userIndexClient.registerBot(bot); } - addBotToCommunity( - id: CommunityIdentifier, + addBot( + id: CommunityIdentifier | GroupChatIdentifier, + botId: string, + grantedPermissions: SlashCommandPermissions, + ): Promise { + switch (id.kind) { + case "community": + return this.communityClient(id.communityId).addBot(botId, grantedPermissions); + case "group_chat": + return this.getGroupClient(id.groupId).addBot(botId, grantedPermissions); + } + } + + updateBot( + id: CommunityIdentifier | GroupChatIdentifier, botId: string, grantedPermissions: SlashCommandPermissions, ): Promise { - return this.communityClient(id.communityId).addBot(botId, grantedPermissions); + switch (id.kind) { + case "community": + return this.communityClient(id.communityId).updateBot(botId, grantedPermissions); + case "group_chat": + return this.getGroupClient(id.groupId).updateBot(botId, grantedPermissions); + } } - removeBotFromCommunity(id: CommunityIdentifier, botId: string): Promise { - return this.communityClient(id.communityId).removeBot(botId); + removeBot(id: CommunityIdentifier | GroupChatIdentifier, botId: string): Promise { + switch (id.kind) { + case "community": + return this.communityClient(id.communityId).removeBot(botId); + case "group_chat": + return this.getGroupClient(id.groupId).removeBot(botId); + } } getBots(initialLoad: boolean): Stream { diff --git a/frontend/openchat-agent/src/services/userIndex/mappers.ts b/frontend/openchat-agent/src/services/userIndex/mappers.ts index 1082c57d3b..4a2d082a7d 100644 --- a/frontend/openchat-agent/src/services/userIndex/mappers.ts +++ b/frontend/openchat-agent/src/services/userIndex/mappers.ts @@ -699,8 +699,7 @@ export function externalBotMatch( .replace("{blobType}", "avatar")}/${botId}/${id}`, ), id: botId, - score: match.score, - owner: principalBytesToString(match.owner), + ownerId: principalBytesToString(match.owner), description: match.description, commands: match.commands.map(externalBotCommand), }; diff --git a/frontend/openchat-agent/src/typebox.ts b/frontend/openchat-agent/src/typebox.ts index fef552f21e..b4d07d3c6c 100644 --- a/frontend/openchat-agent/src/typebox.ts +++ b/frontend/openchat-agent/src/typebox.ts @@ -180,6 +180,12 @@ export const GroupDisableInviteCodeArgs = Type.Object({ correlation_id: Type.BigInt(), }); +export type GroupRemoveBotResponse = Static; +export const GroupRemoveBotResponse = Type.Union([ + Type.Literal("Success"), + Type.Literal("NotAuthorized"), +]); + export type GroupRegisterProposalVoteV2Response = Static< typeof GroupRegisterProposalVoteV2Response >; @@ -271,6 +277,14 @@ export const GroupDeclineInvitiationResponse = Type.Union([ Type.Literal("NotInvited"), ]); +export type GroupUpdateBotResponse = Static; +export const GroupUpdateBotResponse = Type.Union([ + Type.Literal("Success"), + Type.Literal("ChatFrozen"), + Type.Literal("NotAuthorized"), + Type.Literal("NotFound"), +]); + export type GroupSelectedUpdatesArgs = Static; export const GroupSelectedUpdatesArgs = Type.Object({ updates_since: Type.BigInt(), @@ -315,6 +329,14 @@ export const GroupFollowThreadResponse = Type.Union([ Type.Literal("GroupFrozen"), ]); +export type GroupAddBotResponse = Static; +export const GroupAddBotResponse = Type.Union([ + Type.Literal("Success"), + Type.Literal("ChatFrozen"), + Type.Literal("NotAuthorized"), + Type.Literal("AlreadyAdded"), +]); + export type ChannelId = Static; export const ChannelId = Type.BigInt(); @@ -3037,6 +3059,14 @@ export const CommunityEventsArgs = Type.Object({ latest_known_update: Type.Optional(Type.Union([Type.BigInt(), Type.Undefined()])), }); +export type CommunityUpdateBotResponse = Static; +export const CommunityUpdateBotResponse = Type.Union([ + Type.Literal("Success"), + Type.Literal("CommunityFrozen"), + Type.Literal("NotAuthorized"), + Type.Literal("NotFound"), +]); + export type CommunityAcceptP2pSwapArgs = Static; export const CommunityAcceptP2pSwapArgs = Type.Object({ channel_id: ChannelId, @@ -3181,7 +3211,7 @@ export const CommunityFollowThreadArgs = Type.Object({ export type CommunityAddBotResponse = Static; export const CommunityAddBotResponse = Type.Union([ Type.Literal("Success"), - Type.Literal("ChatFrozen"), + Type.Literal("CommunityFrozen"), Type.Literal("NotAuthorized"), Type.Literal("AlreadyAdded"), ]); @@ -5206,6 +5236,12 @@ export const CommunityBlockUserArgs = Type.Object({ user_id: UserId, }); +export type CommunityUpdateBotArgs = Static; +export const CommunityUpdateBotArgs = Type.Object({ + bot_id: UserId, + granted_permissions: SlashCommandPermissions, +}); + export type CommunityCreateChannelResponse = Static; export const CommunityCreateChannelResponse = Type.Union([ Type.Object({ @@ -5404,6 +5440,11 @@ export const GroupUpdateGroupResponse = Type.Union([ Type.Literal("InternalError"), ]); +export type GroupRemoveBotArgs = Static; +export const GroupRemoveBotArgs = Type.Object({ + bot_id: UserId, +}); + export type GroupBlockUserArgs = Static; export const GroupBlockUserArgs = Type.Object({ user_id: UserId, @@ -5416,6 +5457,18 @@ export const GroupRemoveParticipantArgs = Type.Object({ correlation_id: Type.BigInt(), }); +export type GroupUpdateBotArgs = Static; +export const GroupUpdateBotArgs = Type.Object({ + bot_id: UserId, + granted_permissions: SlashCommandPermissions, +}); + +export type GroupAddBotArgs = Static; +export const GroupAddBotArgs = Type.Object({ + bot_id: UserId, + granted_permissions: SlashCommandPermissions, +}); + export type UserSearchMessagesArgs = Static; export const UserSearchMessagesArgs = Type.Object({ user_id: UserId, diff --git a/frontend/openchat-agent/src/utils/caching.ts b/frontend/openchat-agent/src/utils/caching.ts index cc584d564d..10eec4281a 100644 --- a/frontend/openchat-agent/src/utils/caching.ts +++ b/frontend/openchat-agent/src/utils/caching.ts @@ -255,7 +255,12 @@ const migrations: Record> = { createBotsStore(db, principal, tx), ]); }, - 121: clearEvents, + 121: async (db, principal, tx) => { + await Promise.all([ + clearEvents(db, principal, tx), + clearGroupDetailsStore(db, principal, tx), + ]); + }, }; async function migrate( diff --git a/frontend/openchat-agent/src/utils/chat.ts b/frontend/openchat-agent/src/utils/chat.ts index 618a0a0617..9bd10c4733 100644 --- a/frontend/openchat-agent/src/utils/chat.ts +++ b/frontend/openchat-agent/src/utils/chat.ts @@ -102,11 +102,16 @@ export function mergeCommunityDetails( updates.userGroups, updates.userGroupsDeleted, ), - bots: mergeThings((b) => b.id, identity, previous.bots, { - added: [], - updated: updates.botsAddedOrUpdated, - removed: updates.botsRemoved, - }), + bots: mergeThings( + (b) => b.id, + (_, updated) => updated, + previous.bots, + { + added: [], + updated: updates.botsAddedOrUpdated, + removed: updates.botsRemoved, + }, + ), }; } @@ -145,6 +150,16 @@ export function mergeGroupChatDetails( updates.pinnedMessagesRemoved, ), rules: updates.rules ?? previous.rules, + bots: mergeThings( + (b) => b.id, + (_, updated) => updated, + previous.bots, + { + added: [], + updated: updates.botsAddedOrUpdated, + removed: updates.botsRemoved, + }, + ), }; } diff --git a/frontend/openchat-client/src/openchat.ts b/frontend/openchat-client/src/openchat.ts index 3bd3de822e..1b8d951e9c 100644 --- a/frontend/openchat-client/src/openchat.ts +++ b/frontend/openchat-client/src/openchat.ts @@ -1924,6 +1924,17 @@ export class OpenChat extends EventTarget { } } + canManageBots(id: ChatIdentifier | CommunityIdentifier): boolean { + switch (id.kind) { + case "community": + return this.#communityPredicate(id, ({ membership: { role } }) => + hasOwnerRights(role), + ); + default: + return this.#chatPredicate(id, ({ membership: { role } }) => hasOwnerRights(role)); + } + } + canAddMembers(id: ChatIdentifier): boolean { return this.#chatPredicate(id, canAddMembers); } @@ -3159,6 +3170,11 @@ export class OpenChat extends EventTarget { chatStateStore.setProp(serverChat.id, "invitedUsers", resp.invitedUsers); chatStateStore.setProp(serverChat.id, "pinnedMessages", resp.pinnedMessages); chatStateStore.setProp(serverChat.id, "rules", resp.rules); + chatStateStore.setProp( + serverChat.id, + "bots", + resp.bots.reduce((all, b) => all.set(b.id, b.permissions), new Map()), + ); } await this.#updateUserStoreFromEvents(serverChat.id, []); } @@ -7823,29 +7839,46 @@ export class OpenChat extends EventTarget { }); } - addBotToCommunity( - id: CommunityIdentifier, + addBot( + id: CommunityIdentifier | GroupChatIdentifier, + botId: string, + grantedPermissions: SlashCommandPermissions, + ): Promise { + return this.#sendRequest({ + kind: "addBot", + id, + botId, + grantedPermissions, + }).catch((err) => { + this.#logger.error("Error adding bot to group or community", err); + return false; + }); + } + + updateBot( + id: CommunityIdentifier | GroupChatIdentifier, botId: string, grantedPermissions: SlashCommandPermissions, ): Promise { return this.#sendRequest({ - kind: "addBotToCommunity", + kind: "updateBot", id, botId, grantedPermissions, }).catch((err) => { - this.#logger.error("Error adding bot to community", err); + this.#logger.error("Error adding bot to group or community", err); return false; }); } - removeBotFromCommunity(id: CommunityIdentifier, botId: string): Promise { + // TODO - probably need to think about local updates here + removeBot(id: CommunityIdentifier | GroupChatIdentifier, botId: string): Promise { return this.#sendRequest({ - kind: "removeBotFromCommunity", + kind: "removeBot", id, botId, }).catch((err) => { - this.#logger.error("Error removing bot from community", err); + this.#logger.error("Error removing bot from group or community", err); return false; }); } diff --git a/frontend/openchat-client/src/stores/chat.ts b/frontend/openchat-client/src/stores/chat.ts index 24a6c6bcbc..20e9d41eb3 100644 --- a/frontend/openchat-client/src/stores/chat.ts +++ b/frontend/openchat-client/src/stores/chat.ts @@ -12,6 +12,7 @@ import type { ChatListScope, ExpiredEventsRange, MessageContext, + SlashCommandPermissions, } from "openchat-shared"; import { compareChats, @@ -89,6 +90,7 @@ export const chatStateStore = createChatSpecificObjectStore( serverEvents: [], expandedDeletedMessages: new Set(), expiredEventRanges: new DRange(), + bots: new Map(), }), ); @@ -98,6 +100,12 @@ const serverEventsStore = createDerivedPropStore [], ); +export const currentChatBots = createDerivedPropStore( + chatStateStore, + "bots", + () => new Map(), +); + export const currentChatUserIds = createDerivedPropStore( chatStateStore, "userIds", diff --git a/frontend/openchat-client/src/utils/testBots.ts b/frontend/openchat-client/src/utils/testBots.ts index 876004abc5..934efc469f 100644 --- a/frontend/openchat-client/src/utils/testBots.ts +++ b/frontend/openchat-client/src/utils/testBots.ts @@ -216,19 +216,17 @@ export const testBots: Bot[] = [ export const testMatches: BotMatch[] = [ { id: "one", - score: 10, name: "Kitten bot", description: "this is just a test bot and it doen't do very much", - owner: "owner", + ownerId: "owner", commands: [killCommand, kickPollCommand], }, { id: "two", - score: 10, name: "Puppy bot", description: "This bot also does not do anything but in this case it has a much longer description. The reason that we need a longer description is so that we can tell that the card still renders ok if there is a lot of text to display. What should we do? Should we truncate it or should we do something else? Show multiple lines? Show the whole thing? Make it expandable?", - owner: "owner", + ownerId: "owner", commands: [ chatCommand, banCommand, diff --git a/frontend/openchat-shared/src/domain/bots.ts b/frontend/openchat-shared/src/domain/bots.ts index 7b7a8b7b5b..e5f1e289eb 100644 --- a/frontend/openchat-shared/src/domain/bots.ts +++ b/frontend/openchat-shared/src/domain/bots.ts @@ -196,7 +196,7 @@ export type ExternalBot = { id: string; ownerId: string; endpoint: string; - description?: string; + description: string; commands: SlashCommandSchema[]; }; diff --git a/frontend/openchat-shared/src/domain/chat/chat.ts b/frontend/openchat-shared/src/domain/chat/chat.ts index a2af2082cc..185d3f7abc 100644 --- a/frontend/openchat-shared/src/domain/chat/chat.ts +++ b/frontend/openchat-shared/src/domain/chat/chat.ts @@ -35,6 +35,7 @@ import type { } from "../community"; import type { ChitEarned } from "../chit"; import type { WalletConfig } from "../crypto"; +import type { BotGroupDetails, SlashCommandPermissions } from "../bots"; export type CallerNotInGroup = { kind: "caller_not_in_group" }; export type CanisterNotFound = { kind: "canister_not_found" }; @@ -1409,6 +1410,7 @@ export type GroupChatDetails = { pinnedMessages: Set; rules: VersionedRules; timestamp: bigint; + bots: BotGroupDetails[]; }; /** @@ -1431,6 +1433,7 @@ export type ChatSpecificState = { serverEvents: EventWrapper[]; expandedDeletedMessages: Set; expiredEventRanges: DRange; + bots: Map; }; export type GroupChatDetailsUpdates = { @@ -1443,6 +1446,8 @@ export type GroupChatDetailsUpdates = { rules?: VersionedRules; invitedUsers?: Set; timestamp: bigint; + botsAddedOrUpdated: BotGroupDetails[]; + botsRemoved: Set; }; export type ChatSummary = DirectChatSummary | MultiUserChat; diff --git a/frontend/openchat-shared/src/domain/search/search.ts b/frontend/openchat-shared/src/domain/search/search.ts index 329ab7f150..c9b42ffda1 100644 --- a/frontend/openchat-shared/src/domain/search/search.ts +++ b/frontend/openchat-shared/src/domain/search/search.ts @@ -33,10 +33,9 @@ export type MessageMatch = { export type BotMatch = { id: string; - score: number; name: string; description: string; - owner: string; + ownerId: string; avatarUrl?: string; commands: SlashCommandSchema[]; }; diff --git a/frontend/openchat-shared/src/domain/worker.ts b/frontend/openchat-shared/src/domain/worker.ts index 4fdc811b6e..f51e9e61ac 100644 --- a/frontend/openchat-shared/src/domain/worker.ts +++ b/frontend/openchat-shared/src/domain/worker.ts @@ -412,19 +412,27 @@ export type WorkerRequest = | MessageActivityFeed | MarkActivityFeedRead | DeleteUser - | AddBotToCommunity - | RemoveBotFromCommunity; + | AddBot + | RemoveBot + | UpdateBot; -type AddBotToCommunity = { - kind: "addBotToCommunity"; - id: CommunityIdentifier; +type AddBot = { + kind: "addBot"; + id: CommunityIdentifier | GroupChatIdentifier; botId: string; grantedPermissions: SlashCommandPermissions; }; -type RemoveBotFromCommunity = { - kind: "removeBotFromCommunity"; - id: CommunityIdentifier; +type UpdateBot = { + kind: "updateBot"; + id: CommunityIdentifier | GroupChatIdentifier; + botId: string; + grantedPermissions: SlashCommandPermissions; +}; + +type RemoveBot = { + kind: "removeBot"; + id: CommunityIdentifier | GroupChatIdentifier; botId: string; }; @@ -2248,6 +2256,10 @@ export type WorkerResult = T extends Init ? void : T extends DeleteUser ? boolean - : T extends AddBotToCommunity + : T extends AddBot + ? boolean + : T extends RemoveBot + ? boolean + : T extends UpdateBot ? boolean : never; diff --git a/frontend/openchat-worker/src/worker.ts b/frontend/openchat-worker/src/worker.ts index abd5af5261..1efa20bf36 100644 --- a/frontend/openchat-worker/src/worker.ts +++ b/frontend/openchat-worker/src/worker.ts @@ -1867,19 +1867,27 @@ self.addEventListener("message", (msg: MessageEvent) => executeThenReply(payload, correlationId, agent.deleteUser(payload.userId)); break; - case "addBotToCommunity": + case "addBot": executeThenReply( payload, correlationId, - agent.addBotToCommunity(payload.id, payload.botId, payload.grantedPermissions), + agent.addBot(payload.id, payload.botId, payload.grantedPermissions), ); break; - case "removeBotFromCommunity": + case "updateBot": executeThenReply( payload, correlationId, - agent.removeBotFromCommunity(payload.id, payload.botId), + agent.updateBot(payload.id, payload.botId, payload.grantedPermissions), + ); + break; + + case "removeBot": + executeThenReply( + payload, + correlationId, + agent.removeBot(payload.id, payload.botId), ); break; diff --git a/tsBindings/community/addBot/CommunityAddBotResponse.ts b/tsBindings/community/addBot/CommunityAddBotResponse.ts index efefb10f45..30861e67d1 100644 --- a/tsBindings/community/addBot/CommunityAddBotResponse.ts +++ b/tsBindings/community/addBot/CommunityAddBotResponse.ts @@ -1,3 +1,3 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type CommunityAddBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "AlreadyAdded"; +export type CommunityAddBotResponse = "Success" | "CommunityFrozen" | "NotAuthorized" | "AlreadyAdded"; diff --git a/tsBindings/community/updateBot/CommunityUpdateBotArgs.ts b/tsBindings/community/updateBot/CommunityUpdateBotArgs.ts new file mode 100644 index 0000000000..a1b0e84e4d --- /dev/null +++ b/tsBindings/community/updateBot/CommunityUpdateBotArgs.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SlashCommandPermissions } from "../../shared/SlashCommandPermissions"; +import type { UserId } from "../../shared/UserId"; + +export type CommunityUpdateBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; diff --git a/tsBindings/community/updateBot/CommunityUpdateBotResponse.ts b/tsBindings/community/updateBot/CommunityUpdateBotResponse.ts new file mode 100644 index 0000000000..8c951aa9fd --- /dev/null +++ b/tsBindings/community/updateBot/CommunityUpdateBotResponse.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type CommunityUpdateBotResponse = "Success" | "CommunityFrozen" | "NotAuthorized" | "NotFound"; diff --git a/tsBindings/group/addBot/GroupAddBotArgs.ts b/tsBindings/group/addBot/GroupAddBotArgs.ts new file mode 100644 index 0000000000..c055dcfebc --- /dev/null +++ b/tsBindings/group/addBot/GroupAddBotArgs.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SlashCommandPermissions } from "../../shared/SlashCommandPermissions"; +import type { UserId } from "../../shared/UserId"; + +export type GroupAddBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; diff --git a/tsBindings/group/addBot/GroupAddBotResponse.ts b/tsBindings/group/addBot/GroupAddBotResponse.ts new file mode 100644 index 0000000000..0a81a9f8bf --- /dev/null +++ b/tsBindings/group/addBot/GroupAddBotResponse.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type GroupAddBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "AlreadyAdded"; diff --git a/tsBindings/group/removeBot/GroupRemoveBotArgs.ts b/tsBindings/group/removeBot/GroupRemoveBotArgs.ts new file mode 100644 index 0000000000..62854f13b4 --- /dev/null +++ b/tsBindings/group/removeBot/GroupRemoveBotArgs.ts @@ -0,0 +1,4 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { UserId } from "../../shared/UserId"; + +export type GroupRemoveBotArgs = { bot_id: UserId, }; diff --git a/tsBindings/group/removeBot/GroupRemoveBotResponse.ts b/tsBindings/group/removeBot/GroupRemoveBotResponse.ts new file mode 100644 index 0000000000..72d1d01b49 --- /dev/null +++ b/tsBindings/group/removeBot/GroupRemoveBotResponse.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type GroupRemoveBotResponse = "Success" | "NotAuthorized"; diff --git a/tsBindings/group/updateBot/GroupUpdateBotArgs.ts b/tsBindings/group/updateBot/GroupUpdateBotArgs.ts new file mode 100644 index 0000000000..0df1e6d2d7 --- /dev/null +++ b/tsBindings/group/updateBot/GroupUpdateBotArgs.ts @@ -0,0 +1,5 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { SlashCommandPermissions } from "../../shared/SlashCommandPermissions"; +import type { UserId } from "../../shared/UserId"; + +export type GroupUpdateBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; diff --git a/tsBindings/group/updateBot/GroupUpdateBotResponse.ts b/tsBindings/group/updateBot/GroupUpdateBotResponse.ts new file mode 100644 index 0000000000..f8bfe0e2f2 --- /dev/null +++ b/tsBindings/group/updateBot/GroupUpdateBotResponse.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type GroupUpdateBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "NotFound"; diff --git a/tsBindings/types.d.ts b/tsBindings/types.d.ts index aaf96f40da..e385c8089e 100644 --- a/tsBindings/types.d.ts +++ b/tsBindings/types.d.ts @@ -18,6 +18,7 @@ export type GroupEnableInviteCodeSuccessResult = { code: bigint, }; export type GroupRegisterProposalVoteResponse = "Success" | { "AlreadyVoted": boolean } | "CallerNotInGroup" | "NoEligibleNeurons" | "ProposalMessageNotFound" | "ProposalNotFound" | "ProposalNotAcceptingVotes" | "UserSuspended" | "UserLapsed" | "ChatFrozen" | { "InternalError": string }; export type GroupDisableInviteCodeResponse = "Success" | "NotAuthorized" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; export type GroupDisableInviteCodeArgs = { correlation_id: bigint, }; +export type GroupRemoveBotResponse = "Success" | "NotAuthorized"; export type GroupRegisterProposalVoteV2Response = "Success" | "CallerNotInGroup" | "ProposalMessageNotFound" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; export type GroupPublicSummaryArgs = { invite_code?: bigint | undefined, }; export type GroupRemoveReactionResponse = "Success" | "NoChange" | "MessageNotFound" | "CallerNotInGroup" | "NotAuthorized" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; @@ -27,11 +28,13 @@ export type GroupRulesSuccessResult = { rules?: string | undefined, }; export type GroupBlockUserResponse = "Success" | "CallerNotInGroup" | "CannotBlockSelf" | "CannotBlockUser" | "GroupNotPublic" | { "InternalError": string } | "NotAuthorized" | "UserNotInGroup" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; export type GroupRemoveParticipantResponse = "Success" | "CallerNotInGroup" | "CannotRemoveSelf" | "CannotRemoveUser" | { "InternalError": string } | "NotAuthorized" | "UserNotInGroup" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; export type GroupDeclineInvitiationResponse = "Success" | "NotInvited"; +export type GroupUpdateBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "NotFound"; export type GroupSelectedUpdatesArgs = { updates_since: bigint, }; export type GroupReportMessageResponse = "Success" | "UserSuspended" | "UserLapsed" | "ChatFrozen" | "CallerNotInGroup" | "NotAuthorized" | "MessageNotFound" | "AlreadyReported" | { "InternalError": string }; export type GroupEditMessageResponse = "Success" | "MessageNotFound" | "CallerNotInGroup" | "UserSuspended" | "UserLapsed" | "ChatFrozen"; export type GroupSummaryArgs = { }; export type GroupFollowThreadResponse = "Success" | "AlreadyFollowing" | "ThreadNotFound" | "UserNotInGroup" | "UserSuspended" | "UserLapsed" | "GroupFrozen"; +export type GroupAddBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "AlreadyAdded"; export type ChannelId = bigint; export type UserManageFavouriteChatsResponse = "Success" | "UserSuspended"; export type UserMessageActivitySummary = { read_up_to: bigint, latest_event_timestamp: bigint, unread_count: number, }; @@ -327,6 +330,7 @@ export type CommunitySendMessageResponse = { "Success": CommunitySendMessageSucc export type CommunityEventsByIndexArgs = { channel_id: ChannelId, thread_root_message_index?: MessageIndex | undefined, events: Array, latest_known_update?: bigint | undefined, }; export type CommunityLocalUserIndexResponse = { "Success": TSBytes }; export type CommunityEventsArgs = { channel_id: ChannelId, thread_root_message_index?: MessageIndex | undefined, start_index: EventIndex, ascending: boolean, max_messages: number, max_events: number, latest_known_update?: bigint | undefined, }; +export type CommunityUpdateBotResponse = "Success" | "CommunityFrozen" | "NotAuthorized" | "NotFound"; export type CommunityAcceptP2pSwapArgs = { channel_id: ChannelId, thread_root_message_index?: MessageIndex | undefined, message_id: MessageId, pin?: string | undefined, new_achievement: boolean, }; export type CommunityCreateChannelSuccessResult = { channel_id: ChannelId, }; export type CommunitySelectedUpdatesArgs = { invite_code?: bigint | undefined, updates_since: bigint, }; @@ -341,7 +345,7 @@ export type CommunitySetMemberDisplayNameResponse = "Success" | "CommunityFrozen export type CommunitySummaryArgs = { invite_code?: bigint | undefined, }; export type CommunityFollowThreadResponse = "Success" | "AlreadyFollowing" | "ThreadNotFound" | "ChannelNotFound" | "UserNotInChannel" | "UserNotInCommunity" | "UserSuspended" | "CommunityFrozen" | "UserLapsed"; export type CommunityFollowThreadArgs = { channel_id: ChannelId, thread_root_message_index: MessageIndex, new_achievement: boolean, }; -export type CommunityAddBotResponse = "Success" | "ChatFrozen" | "NotAuthorized" | "AlreadyAdded"; +export type CommunityAddBotResponse = "Success" | "CommunityFrozen" | "NotAuthorized" | "AlreadyAdded"; export type CommunityDeleteChannelResponse = "Success" | "CommunityFrozen" | "UserSuspended" | "UserNotInCommunity" | "ChannelNotFound" | "UserNotInChannel" | "NotAuthorized" | "UserLapsed"; export type CommunityDeleteChannelArgs = { channel_id: ChannelId, }; export type NotificationsIndexPushSubscriptionResponse = "Success" | { "InternalError": string }; @@ -554,6 +558,7 @@ export type CommunityAddMembersToChannelFailedResult = { users_already_in_channe export type CommunityRemoveBotArgs = { bot_id: UserId, }; export type CommunityChangeChannelRoleArgs = { channel_id: ChannelId, user_id: UserId, new_role: GroupRole, }; export type CommunityBlockUserArgs = { user_id: UserId, }; +export type CommunityUpdateBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; export type CommunityCreateChannelResponse = { "Success": CommunityCreateChannelSuccessResult } | { "NameTooShort": FieldTooShortResult } | { "NameTooLong": FieldTooLongResult } | "NameReserved" | { "DescriptionTooLong": FieldTooLongResult } | { "RulesTooShort": FieldTooShortResult } | { "RulesTooLong": FieldTooLongResult } | { "AvatarTooBig": FieldTooLongResult } | "AccessGateInvalid" | { "MaxChannelsCreated": number } | "NameTaken" | "UserSuspended" | "NotAuthorized" | "CommunityFrozen" | "ExternalUrlInvalid" | { "InternalError": string } | "UserLapsed"; export type CommunityImportGroupArgs = { group_id: ChatId, }; export type CommunityUpdateChannelResponse = { "SuccessV2": CommunityUpdateChannelSuccessResult } | "NotAuthorized" | "UserNotInCommunity" | "ChannelNotFound" | "UserNotInChannel" | { "NameTooShort": FieldTooShortResult } | { "NameTooLong": FieldTooLongResult } | "NameReserved" | { "DescriptionTooLong": FieldTooLongResult } | { "AvatarTooBig": FieldTooLongResult } | "AccessGateInvalid" | "NameTaken" | { "RulesTooLong": FieldTooLongResult } | { "RulesTooShort": FieldTooShortResult } | "UserSuspended" | "ExternalUrlInvalid" | "CommunityFrozen" | "UserLapsed"; @@ -569,8 +574,11 @@ export type GroupCancelInvitesArgs = { user_ids: Array, }; export type GroupChangeRoleArgs = { user_id: UserId, new_role: GroupRole, correlation_id: bigint, }; export type GroupUnblockUserArgs = { user_id: UserId, correlation_id: bigint, }; export type GroupUpdateGroupResponse = { "SuccessV2": GroupUpdateGroupSuccessResult } | "NotAuthorized" | "CallerNotInGroup" | { "NameTooShort": FieldTooShortResult } | { "NameTooLong": FieldTooLongResult } | "NameReserved" | { "DescriptionTooLong": FieldTooLongResult } | { "RulesTooShort": FieldTooShortResult } | { "RulesTooLong": FieldTooLongResult } | { "AvatarTooBig": FieldTooLongResult } | "AccessGateInvalid" | "NameTaken" | "UserSuspended" | "UserLapsed" | "ChatFrozen" | "InternalError"; +export type GroupRemoveBotArgs = { bot_id: UserId, }; export type GroupBlockUserArgs = { user_id: UserId, correlation_id: bigint, }; export type GroupRemoveParticipantArgs = { user_id: UserId, correlation_id: bigint, }; +export type GroupUpdateBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; +export type GroupAddBotArgs = { bot_id: UserId, granted_permissions: SlashCommandPermissions, }; export type UserSearchMessagesArgs = { user_id: UserId, search_term: string, max_results: number, }; export type UserCommunitySummaryUpdates = { community_id: CommunityId, channels: Array, index?: number | undefined, archived?: boolean | undefined, pinned?: Array | undefined, }; export type UserGroupChatSummary = { chat_id: ChatId, local_user_index_canister_id: TSBytes, read_by_me_up_to?: MessageIndex | undefined, threads_read: Record, archived: boolean, date_read_pinned?: bigint | undefined, };