ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
import {z} from "zod";
|
|
|
|
|
|
|
|
import * as people from "./people";
|
|
|
|
|
|
|
|
export type ServerUpdateBotData = z.infer<typeof server_update_bot_schema>;
|
|
|
|
export type ServerAddBotData = z.infer<typeof server_add_bot_schema>;
|
|
|
|
export type Bot = Omit<ServerAddBotData, "services">;
|
|
|
|
|
|
|
|
export type Services = z.infer<typeof services_schema>;
|
|
|
|
|
|
|
|
export type BotDataParams = {
|
|
|
|
realm_bots: ServerAddBotData[];
|
|
|
|
};
|
|
|
|
|
|
|
|
const bots = new Map<number, Bot>();
|
|
|
|
const services = new Map<number, Services>();
|
|
|
|
|
|
|
|
// Define zod schema for data validation
|
|
|
|
const basic_bot_schema = z.object({
|
|
|
|
api_key: z.string(),
|
|
|
|
avatar_url: z.string(),
|
|
|
|
bot_type: z.number(),
|
|
|
|
default_all_public_streams: z.boolean(),
|
2024-02-09 21:29:42 +01:00
|
|
|
default_events_register_stream: z.string().nullable(),
|
|
|
|
default_sending_stream: z.string().nullable(),
|
ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
email: z.string(),
|
|
|
|
full_name: z.string(),
|
|
|
|
is_active: z.boolean(),
|
2023-08-22 03:53:15 +02:00
|
|
|
owner_id: z.number().nullable(),
|
ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
user_id: z.number(),
|
|
|
|
});
|
|
|
|
|
|
|
|
const outgoing_service_schema = z.object({
|
|
|
|
base_url: z.string(),
|
|
|
|
interface: z.number(),
|
|
|
|
token: z.string(),
|
|
|
|
});
|
|
|
|
|
|
|
|
const embedded_service_schema = z.object({
|
|
|
|
config_data: z.record(z.string()),
|
|
|
|
service_name: z.string(),
|
|
|
|
});
|
|
|
|
|
|
|
|
const services_schema = z.union([
|
|
|
|
z.array(outgoing_service_schema),
|
|
|
|
z.array(embedded_service_schema),
|
|
|
|
]);
|
|
|
|
|
|
|
|
const server_update_bot_schema = basic_bot_schema.extend({
|
|
|
|
services: services_schema,
|
|
|
|
});
|
|
|
|
|
|
|
|
const server_add_bot_schema = server_update_bot_schema.extend({
|
|
|
|
bot_type: z.number(),
|
|
|
|
email: z.string(),
|
|
|
|
is_active: z.boolean(),
|
|
|
|
});
|
|
|
|
|
|
|
|
export function all_user_ids(): number[] {
|
|
|
|
return [...bots.keys()];
|
|
|
|
}
|
|
|
|
|
|
|
|
export function add(bot_data: ServerAddBotData): void {
|
|
|
|
const {services: bot_services, ...clean_bot} = server_add_bot_schema.parse(bot_data);
|
|
|
|
bots.set(clean_bot.user_id, clean_bot);
|
|
|
|
|
|
|
|
services.set(clean_bot.user_id, bot_services);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function del(bot_id: number): void {
|
|
|
|
bots.delete(bot_id);
|
|
|
|
services.delete(bot_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function update(bot_id: number, bot_update: ServerUpdateBotData): void {
|
|
|
|
const bot = bots.get(bot_id)!;
|
|
|
|
Object.assign(bot, server_update_bot_schema.deepPartial().parse(bot_update));
|
|
|
|
|
|
|
|
// We currently only support one service per bot.
|
|
|
|
const service = services.get(bot_id)![0];
|
2024-05-30 19:07:58 +02:00
|
|
|
if (
|
|
|
|
service !== undefined &&
|
|
|
|
bot_update.services !== undefined &&
|
|
|
|
bot_update.services.length > 0
|
|
|
|
) {
|
ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
Object.assign(service, services_schema.parse(bot_update.services)[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_all_bots_for_current_user(): Bot[] {
|
|
|
|
const ret = [];
|
|
|
|
for (const bot of bots.values()) {
|
2023-08-22 03:53:15 +02:00
|
|
|
if (bot.owner_id !== null && people.is_my_user_id(bot.owner_id)) {
|
ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
ret.push(bot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_editable(): Bot[] {
|
|
|
|
const ret = [];
|
|
|
|
for (const bot of bots.values()) {
|
2023-08-22 03:53:15 +02:00
|
|
|
if (bot.is_active && bot.owner_id !== null && people.is_my_user_id(bot.owner_id)) {
|
ts: Migrate `bot_data.js` to TypeScript.
Add type annotations. Create custom types for Bot and Service.
Add zod data validation for incoming bot data from server.
Based on `zerver/openapi/zulip.yaml` description, `add` operation
(`op`) carries data that follows `Bot` structure. So taking
reference from `bot` structure, I create `ServerAddBotData` zod
schema and infer its type. Similarly, `update` operation carries
data that follows `BasicBot`, so I create `ServerUpdateBotData`.
Note that `Bot` inherits from `BasicBot`.
`zerver/openapi/zulip.yaml` describes that `services` in `BasicBot`
can be one of two objects, one with `{base_url, token, interface}`,
another with `{service_name, config_data}`. Therefore, I create
two corresponding schema and infer their types.
Fix two test cases `bot_data.test.js` and `settings_bots.test.js`
whose synthetic objects should have had followed the schema.
2023-07-21 10:41:35 +02:00
|
|
|
ret.push(bot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_all_bots_owned_by_user(user_id: number): Bot[] {
|
|
|
|
const ret = [];
|
|
|
|
for (const bot of bots.values()) {
|
|
|
|
if (bot.owner_id === user_id && bot.is_active) {
|
|
|
|
ret.push(bot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get(bot_id: number): Bot | undefined {
|
|
|
|
return bots.get(bot_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function get_services(bot_id: number): Services | undefined {
|
|
|
|
return services.get(bot_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function initialize(params: BotDataParams): void {
|
|
|
|
bots.clear();
|
|
|
|
for (const bot of params.realm_bots) {
|
|
|
|
add(bot);
|
|
|
|
}
|
|
|
|
}
|