Skip to content

Commit

Permalink
Filter messages based on regular expressions (#4987)
Browse files Browse the repository at this point in the history
  • Loading branch information
megrogan authored Dec 12, 2023
1 parent 4334771 commit 91512f0
Show file tree
Hide file tree
Showing 30 changed files with 290 additions and 57 deletions.
4 changes: 3 additions & 1 deletion backend/canisters/registry/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::model::tokens::{TokenMetrics, Tokens};
use candid::Principal;
use canister_state_macros::canister_state;
use model::message_filters::MessageFilters;
use registry_canister::NervousSystemDetails;
use registry_canister::{MessageFilterSummary, NervousSystemDetails};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashSet;
Expand Down Expand Up @@ -55,6 +55,7 @@ impl RuntimeState {
governance_principals: self.data.governance_principals.iter().copied().collect(),
tokens: self.data.tokens.get_all().iter().map(|t| t.into()).collect(),
nervous_systems: self.data.nervous_systems.get_all().iter().map(|ns| ns.into()).collect(),
message_filters: self.data.message_filters.added_since(0),
failed_sns_launches: self.data.failed_sns_launches.iter().copied().collect(),
canister_ids: CanisterIds {
proposals_bot: self.data.proposals_bot_canister_id,
Expand Down Expand Up @@ -164,6 +165,7 @@ pub struct Metrics {
pub governance_principals: Vec<Principal>,
pub tokens: Vec<TokenMetrics>,
pub nervous_systems: Vec<NervousSystemMetrics>,
pub message_filters: Vec<MessageFilterSummary>,
pub failed_sns_launches: Vec<CanisterId>,
pub canister_ids: CanisterIds,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl MessageFilters {
.iter()
.filter(|f| f.last_updated > since)
.enumerate()
.filter_map(|(i, f)| if f.regex.is_some() { Some(i as u64) } else { None })
.filter_map(|(i, f)| if f.regex.is_none() { Some(i as u64) } else { None })
.collect()
}
}
10 changes: 10 additions & 0 deletions frontend/app/src/components/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
removeHotGroupExclusion,
setCommunityModerationFlags,
unfreezeGroup,
addMessageFilter,
removeMessageFilter,
};
(<any>window).platformOperator = {
setGroupUpgradeConcurrency,
Expand Down Expand Up @@ -176,6 +178,14 @@
});
}
function addMessageFilter(regex: string): void {
client.addMessageFilter(regex);
}
function removeMessageFilter(id: bigint): void {
client.removeMessageFilter(id);
}
function deleteChannelMessage(
communityId: string,
channelId: string,
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,6 @@
"offlineMessage": "离线",
"offlineError": "抱歉 - 您目前似乎处于离线状态",
"renderPreviews": "自动渲染链接预览",
"messageBlocked": "由于发件人被阻止,邮件被隐藏",
"tokenSwap": {
"swap": "兑换",
"quote": "报价",
Expand All @@ -1205,5 +1204,6 @@
"swapToken": "交换{tokenIn}",
"swapTokenTo": "将 {tokenIn} 交换为 {tokenOut}",
"quoteTooLow": "所报的最佳费率是 {rate} {tokenOut} / {tokenIn} @{dex}。这将从 {amountIn} {tokenIn} 兑换 {amountOut} {tokenOut} 。仅当报价金额超过 {minAmountOut} 时,您才可以进行交换。"
}
},
"messageBlocked": "消息已隐藏"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,6 @@
"offlineMessage": "Offline",
"offlineError": "Entschuldigung, es sieht so aus, als wären Sie im Moment offline",
"renderPreviews": "Linkvorschauen automatisch rendern",
"messageBlocked": "Nachricht ausgeblendet, da der Absender blockiert ist",
"tokenSwap": {
"swap": "Tauschen",
"quote": "Zitat",
Expand All @@ -1206,5 +1205,6 @@
"swapToken": "Tausche {tokenIn}",
"swapTokenTo": "Tauschen Sie {tokenIn} gegen {tokenOut} aus",
"quoteTooLow": "Der beste angegebene Tarif ist {rate} {tokenOut} pro {tokenIn} ab {dex}. Dies ergibt {amountOut} {tokenOut} für {amountIn} {tokenIn}. Sie können nur tauschen, wenn der angegebene Betrag {minAmountOut} überschreitet."
}
},
"messageBlocked": "Nachricht ausgeblendet"
}
2 changes: 1 addition & 1 deletion frontend/app/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1196,5 +1196,5 @@
"disabled": "Disappearing messages disabled"
},
"offlineMessage": "Offline",
"messageBlocked": "Message hidden because sender is blocked"
"messageBlocked": "Message hidden"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,6 @@
"offlineMessage": "Desconectado",
"offlineError": "Lo sentimos, parece que estás desconectado en este momento.",
"renderPreviews": "Vistas previas de enlaces de renderizado automático",
"messageBlocked": "Mensaje oculto porque el remitente está bloqueado",
"tokenSwap": {
"swap": "Intercambio",
"quote": "Cita",
Expand All @@ -1206,5 +1205,6 @@
"swapToken": "Intercambiar {tokenIn}",
"swapTokenTo": "Intercambiar {tokenIn} por {tokenOut}",
"quoteTooLow": "La mejor tarifa cotizada es {rate} {tokenOut} por {tokenIn} de {dex}. Esto da {amountOut} {tokenOut} para {amountIn} {tokenIn}. Solo puede intercambiar si el monto cotizado excede {minAmountOut}."
}
},
"messageBlocked": "Mensaje oculto"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,6 @@
"offlineMessage": "Hors ligne",
"offlineError": "Désolé, il semble que vous soyez hors ligne pour le moment",
"renderPreviews": "Aperçus des liens avec rendu automatique",
"messageBlocked": "Message masqué car l'expéditeur est bloqué",
"tokenSwap": {
"swap": "Échanger",
"quote": "Citation",
Expand All @@ -1204,5 +1203,6 @@
"swapToken": "Échanger {tokenIn}",
"swapTokenTo": "Remplacer {tokenIn} par {tokenOut}",
"quoteTooLow": "Le meilleur tarif indiqué est de {rate} {tokenOut} pour {tokenIn} à partir de {dex}. Cela donne {amountOut} {tokenOut} pour {amountIn} {tokenIn}. Vous ne pouvez échanger que si le montant indiqué dépasse {minAmountOut}."
}
},
"messageBlocked": "Message masqué"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,6 @@
"offlineMessage": "disconnesso",
"offlineError": "Siamo spiacenti, sembra che tu sia offline al momento",
"renderPreviews": "Anteprime dei collegamenti con rendering automatico",
"messageBlocked": "Messaggio nascosto perché il mittente è bloccato",
"tokenSwap": {
"swap": "Scambio",
"quote": "Citazione",
Expand All @@ -1204,5 +1203,6 @@
"swapToken": "Scambia {tokenIn}",
"swapTokenTo": "Scambia {tokenIn} in {tokenOut}",
"quoteTooLow": "La migliore tariffa indicata è {rate} {tokenOut} per {tokenIn} da {dex}. Questo dà {amountOut} {tokenOut} per {amountIn} {tokenIn}. Puoi scambiare solo se l'importo indicato supera {minAmountOut}."
}
},
"messageBlocked": "Messaggio nascosto"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/iw.json
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,6 @@
"offlineMessage": "לא מקוון",
"offlineError": "סליחה - נראה שאתה במצב לא מקוון כרגע",
"renderPreviews": "תצוגה מקדימה של קישורים לעיבוד אוטומטי",
"messageBlocked": "ההודעה מוסתרת כי השולח חסום",
"tokenSwap": {
"swap": "לְהַחלִיף",
"quote": "ציטוט",
Expand All @@ -1202,5 +1201,6 @@
"swapToken": "החלפה {tokenIn}",
"swapTokenTo": "החלף את {tokenIn} ל-{tokenOut}",
"quoteTooLow": "התעריף הטוב ביותר שצוטט הוא {rate} {tokenOut} לכל {tokenIn} מ-{dex}. זה נותן {amountOut} {tokenOut} עבור {amountIn} {tokenIn}. אתה יכול להחליף רק אם הסכום הנקוב עולה על {minAmountOut}."
}
},
"messageBlocked": "הודעה מוסתרת"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,6 @@
"offlineMessage": "オフライン",
"offlineError": "申し訳ありませんが、現在オフラインのようです",
"renderPreviews": "自動レンダリングリンクプレビュー",
"messageBlocked": "送信者がブロックされているためメッセージが非表示になりました",
"tokenSwap": {
"swap": "スワップ",
"quote": "引用",
Expand All @@ -1205,5 +1204,6 @@
"swapToken": "{tokenIn}を交換する",
"swapTokenTo": "{tokenIn} を {tokenOut} に交換します",
"quoteTooLow": "見積もられた最良レートは、{rate} からの {tokenOut} あたり {tokenIn} {dex} です。これにより、{amountOut} {tokenOut} の {amountIn} {tokenIn} が得られます。見積金額が {minAmountOut} を超える場合にのみ交換できます。"
}
},
"messageBlocked": "メッセージが隠されています"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1177,7 +1177,6 @@
"offlineMessage": "Не в сети",
"offlineError": "Извините, похоже, вы сейчас не в сети.",
"renderPreviews": "Автоматический предварительный просмотр ссылок",
"messageBlocked": "Сообщение скрыто, поскольку отправитель заблокирован",
"tokenSwap": {
"swap": "Менять",
"quote": "Цитировать",
Expand All @@ -1204,5 +1203,6 @@
"swapToken": "Обмен {tokenIn}",
"swapTokenTo": "Замените {tokenIn} на {tokenOut}",
"quoteTooLow": "Лучшая заявленная ставка составляет {rate} {tokenOut} за {tokenIn} от {dex}. Это дает {amountOut} {tokenOut} для {amountIn} {tokenIn}. Вы можете обменять только в том случае, если заявленная сумма превышает {minAmountOut}."
}
},
"messageBlocked": "Сообщение скрыто"
}
4 changes: 2 additions & 2 deletions frontend/app/src/i18n/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,6 @@
"offlineMessage": "Ngoại tuyến",
"offlineError": "Xin lỗi - có vẻ như bạn đang ngoại tuyến vào lúc này",
"renderPreviews": "Tự động hiển thị bản xem trước liên kết",
"messageBlocked": "Tin nhắn bị ẩn vì người gửi bị chặn",
"tokenSwap": {
"swap": "Tráo đổi",
"quote": "Trích dẫn",
Expand All @@ -1205,5 +1204,6 @@
"swapToken": "Hoán đổi {tokenIn}",
"swapTokenTo": "Hoán đổi {tokenIn} thành {tokenOut}",
"quoteTooLow": "Tỷ giá được trích dẫn tốt nhất là {rate} {tokenOut} trên {tokenIn} từ {dex}. Điều này mang lại {amountOut} {tokenOut} cho {amountIn} {tokenIn}. Bạn chỉ có thể hoán đổi nếu số tiền trích dẫn vượt quá {minAmountOut}."
}
},
"messageBlocked": "Tin nhắn bị ẩn"
}
16 changes: 13 additions & 3 deletions frontend/openchat-agent/src/services/openchatAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2695,7 +2695,7 @@ export class OpenChatAgent extends EventTarget {
return this.getGroupClient(chatId.groupId).convertToCommunity(historyVisible, rules);
}

async getRegistry(): Promise<RegistryValue> {
async getRegistry(): Promise<[RegistryValue, boolean]> {
const current = await getCachedRegistry();

const updates = await this._registryClient.updates(current?.lastUpdated);
Expand All @@ -2711,11 +2711,13 @@ export class OpenChatAgent extends EventTarget {
[...updates.nervousSystemSummary, ...(current?.nervousSystemSummary ?? [])],
(ns) => ns.governanceCanisterId,
),
messageFilters: [ ...current?.messageFilters ?? [], ...updates.messageFiltersAdded ]
.filter((f) => !updates.messageFiltersRemoved.includes(f.id))
};
setCachedRegistry(updated);
return updated;
return [updated, true];
} else if (current !== undefined) {
return current;
return [current, false];
} else {
throw new Error("Registry is empty... this should never happen!");
}
Expand Down Expand Up @@ -2957,4 +2959,12 @@ export class OpenChatAgent extends EventTarget {
diamondMembershipFees(): Promise<DiamondMembershipFees[]> {
return this._userIndexClient.diamondMembershipFees();
}

addMessageFilter(regex: string): Promise<boolean> {
return this._registryClient.addMessageFilter(regex);
}

removeMessageFilter(id: bigint): Promise<boolean> {
return this._registryClient.removeMessageFilter(id);
}
}
31 changes: 31 additions & 0 deletions frontend/openchat-agent/src/services/registry/candid/idl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
export const idlFactory = ({ IDL }) => {
const AddMessageFilterArgs = IDL.Record({ 'regex' : IDL.Text });
const AddMessageFilterResponse = IDL.Variant({
'NotAuthorized' : IDL.Null,
'Success' : IDL.Nat64,
'InvalidRequest' : IDL.Text,
'InternalError' : IDL.Text,
'AlreadyAdded' : IDL.Null,
});
const RemoveMessageFilterArgs = IDL.Record({ 'id' : IDL.Nat64 });
const RemoveMessageFilterResponse = IDL.Variant({
'NotFound' : IDL.Null,
'NotAuthorized' : IDL.Null,
'Success' : IDL.Null,
'InternalError' : IDL.Text,
});
const TimestampMillis = IDL.Nat64;
const UpdatesArgs = IDL.Record({ 'since' : IDL.Opt(TimestampMillis) });
const CanisterId = IDL.Principal;
Expand All @@ -25,15 +40,31 @@ export const idlFactory = ({ IDL }) => {
'proposal_rejection_fee' : IDL.Nat64,
'ledger_canister_id' : CanisterId,
});
const MessageFilterSummary = IDL.Record({
'id' : IDL.Nat64,
'regex' : IDL.Text,
});
const UpdatesResponse = IDL.Variant({
'Success' : IDL.Record({
'last_updated' : TimestampMillis,
'token_details' : IDL.Opt(IDL.Vec(TokenDetails)),
'nervous_system_details' : IDL.Vec(NervousSystemSummary),
'message_filters_removed' : IDL.Vec(IDL.Nat64),
'message_filters_added' : IDL.Vec(MessageFilterSummary),
}),
'SuccessNoUpdates' : IDL.Null,
});
return IDL.Service({
'add_message_filter' : IDL.Func(
[AddMessageFilterArgs],
[AddMessageFilterResponse],
[],
),
'remove_message_filter' : IDL.Func(
[RemoveMessageFilterArgs],
[RemoveMessageFilterResponse],
[],
),
'updates' : IDL.Func([UpdatesArgs], [UpdatesResponse], ['query']),
});
};
Expand Down
22 changes: 22 additions & 0 deletions frontend/openchat-agent/src/services/registry/candid/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export interface Account {
'subaccount' : [] | [Subaccount],
}
export type AccountIdentifier = Uint8Array | number[];
export interface AddMessageFilterArgs { 'regex' : string }
export type AddMessageFilterResponse = { 'NotAuthorized' : null } |
{ 'Success' : bigint } |
{ 'InvalidRequest' : string } |
{ 'InternalError' : string } |
{ 'AlreadyAdded' : null };
export interface AddedToChannelNotification {
'channel_id' : ChannelId,
'community_id' : CommunityId,
Expand Down Expand Up @@ -881,6 +887,7 @@ export interface MessageEventWrapper {
'correlation_id' : bigint,
'expires_at' : [] | [TimestampMillis],
}
export interface MessageFilterSummary { 'id' : bigint, 'regex' : string }
export type MessageId = bigint;
export type MessageIndex = number;
export interface MessageIndexRange {
Expand Down Expand Up @@ -1189,6 +1196,11 @@ export interface PushEventResult {
export type Reaction = string;
export type RegistrationFee = { 'ICP' : ICPRegistrationFee } |
{ 'Cycles' : CyclesRegistrationFee };
export interface RemoveMessageFilterArgs { 'id' : bigint }
export type RemoveMessageFilterResponse = { 'NotFound' : null } |
{ 'NotAuthorized' : null } |
{ 'Success' : null } |
{ 'InternalError' : string };
export interface ReplyContext {
'chat_if_other' : [] | [[Chat, [] | [MessageIndex]]],
'event_index' : EventIndex,
Expand Down Expand Up @@ -1351,6 +1363,8 @@ export type UpdatesResponse = {
'last_updated' : TimestampMillis,
'token_details' : [] | [Array<TokenDetails>],
'nervous_system_details' : Array<NervousSystemSummary>,
'message_filters_removed' : BigUint64Array | bigint[],
'message_filters_added' : Array<MessageFilterSummary>,
}
} |
{ 'SuccessNoUpdates' : null };
Expand Down Expand Up @@ -1409,5 +1423,13 @@ export interface VideoContent {
export type VoteOperation = { 'RegisterVote' : null } |
{ 'DeleteVote' : null };
export interface _SERVICE {
'add_message_filter' : ActorMethod<
[AddMessageFilterArgs],
AddMessageFilterResponse
>,
'remove_message_filter' : ActorMethod<
[RemoveMessageFilterArgs],
RemoveMessageFilterResponse
>,
'updates' : ActorMethod<[UpdatesArgs], UpdatesResponse>,
}
2 changes: 2 additions & 0 deletions frontend/openchat-agent/src/services/registry/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export function updatesResponse(candid: ApiUpdatesResponse): RegistryUpdatesResp
tokens.map((t) => tokenDetails(t)),
) ?? [],
nervousSystemSummary: candid.Success.nervous_system_details.map(nervousSystemSummary),
messageFiltersAdded: candid.Success.message_filters_added,
messageFiltersRemoved: Array.from(candid.Success.message_filters_removed),
};
}
if ("SuccessNoUpdates" in candid) {
Expand Down
20 changes: 20 additions & 0 deletions frontend/openchat-agent/src/services/registry/registry.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,24 @@ export class RegistryClient extends CandidService {
};
return this.handleQueryResponse(() => this.service.updates(args), updatesResponse);
}

addMessageFilter(regex: string): Promise<boolean> {
return this.handleResponse(
this.service.add_message_filter({ regex }),
(resp) => {
if ("Success" in resp) {
console.log(`New message filter id: ${resp.Success}`);
return true;
} else {
console.debug("Error calling add_message_filter", resp);
return false;
}
});
}

removeMessageFilter(id: bigint): Promise<boolean> {
return this.handleResponse(
this.service.remove_message_filter({ id }),
(resp) => "Success" in resp);
}
}
Loading

0 comments on commit 91512f0

Please sign in to comment.