Skip to content

Commit

Permalink
chore: lots of minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed Sep 8, 2024
1 parent 304706d commit fbe8e79
Show file tree
Hide file tree
Showing 15 changed files with 108 additions and 125 deletions.
14 changes: 13 additions & 1 deletion .dev.vars.example
Original file line number Diff line number Diff line change
@@ -1 +1,13 @@
MY_SECRET="MY_SECRET"
BOT_TOKEN=123:xyz
BOT_WEBHOOK=...
BOT_WEBHOOK_SECRET=...
BOT_ADMINS=[1234,5678]

SUPABASE_URL=...
SUPABASE_SERVICE_KEY=...

TELEGRAM_APP_ID=12345678
TELEGRAM_API_HASH=...

APP_PRIVATE_KEY=...
APP_ID=123456
2 changes: 1 addition & 1 deletion src/bot/features/admin/admin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { chatAction } from '@grammyjs/auto-chat-action'
import { Composer } from 'grammy'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'
import { isAdmin } from '#root/bot/filters/is-admin.js'
import { setCommandsHandler } from '#root/bot/handlers/commands/setcommands.js'
import { logHandle } from '#root/bot/helpers/logging.js'
Expand Down
20 changes: 20 additions & 0 deletions src/bot/features/commands/bot-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { chatAction } from '@grammyjs/auto-chat-action'
import { Composer } from 'grammy'
import type { Context } from '#root/bot/grammy-context.js'
import { logHandle } from '#root/bot/helpers/logging.js'

const composer = new Composer<Context>()

const feature = composer.chatType('private')

feature.command(
'botid',
logHandle('command-botid'),
chatAction('typing'),
async (ctx) => {
const botID = ctx.me.id
await ctx.reply(`My ID is ${botID}`)
},
)

export { composer as botIdFeature }
2 changes: 1 addition & 1 deletion src/bot/features/helpers/unhandled.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Composer } from 'grammy'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'
import { logHandle } from '#root/bot/helpers/logging.js'
import { STRINGS } from '../../strings'

Expand Down
2 changes: 1 addition & 1 deletion src/bot/features/welcome.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Composer } from 'grammy'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'
import { logHandle } from '#root/bot/helpers/logging.js'
import { STRINGS } from '../strings'

Expand Down
62 changes: 9 additions & 53 deletions src/bot/handlers/commands/setcommands.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
import type { BotCommand, LanguageCode } from '@grammyjs/types'
import type { BotCommand } from '@grammyjs/types'
import type { CommandContext } from 'grammy'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'

function getLanguageCommand(localeCode: string): BotCommand {
return {
command: 'language',
description: 'language-command-description',
}
}

function getPrivateChatCommands(localeCode: string): BotCommand[] {
function getPrivateChatCommands(): BotCommand[] {
return [
{
command: 'start',
Expand All @@ -18,7 +11,7 @@ function getPrivateChatCommands(localeCode: string): BotCommand[] {
]
}

function getPrivateChatAdminCommands(localeCode: string): BotCommand[] {
function getPrivateChatAdminCommands(): BotCommand[] {
return [
{
command: 'setcommands',
Expand All @@ -27,18 +20,15 @@ function getPrivateChatAdminCommands(localeCode: string): BotCommand[] {
]
}

function getGroupChatCommands(_localeCode: string): BotCommand[] {
function getGroupChatCommands(): BotCommand[] {
return []
}

export async function setCommandsHandler(ctx: CommandContext<Context>) {
const DEFAULT_LANGUAGE_CODE = 'en'

// set private chat commands
await ctx.api.setMyCommands(
[
...getPrivateChatCommands(DEFAULT_LANGUAGE_CODE),
// ...(isMultipleLocales ? [getLanguageCommand(DEFAULT_LANGUAGE_CODE)] : []),
...getPrivateChatCommands(),
],
{
scope: {
Expand All @@ -47,53 +37,19 @@ export async function setCommandsHandler(ctx: CommandContext<Context>) {
},
)

// if (isMultipleLocales) {
// const requests = i18n.locales.map(code =>
// ctx.api.setMyCommands(
// [
// ...getPrivateChatCommands(code),
// ...(isMultipleLocales
// ? [getLanguageCommand(DEFAULT_LANGUAGE_CODE)]
// : []),
// ],
// {
// language_code: code as LanguageCode,
// scope: {
// type: 'all_private_chats',
// },
// },
// ),
// )

// await Promise.all(requests)
// }

// set group chat commands
await ctx.api.setMyCommands(getGroupChatCommands(DEFAULT_LANGUAGE_CODE), {
await ctx.api.setMyCommands(getGroupChatCommands(), {
scope: {
type: 'all_group_chats',
},
})

// if (isMultipleLocales) {
// const requests = i18n.locales.map(code =>
// ctx.api.setMyCommands(getGroupChatCommands(code), {
// language_code: code as LanguageCode,
// scope: {
// type: 'all_group_chats',
// },
// }),
// )

// await Promise.all(requests)
// }

// set private chat commands for owner
await ctx.api.setMyCommands(
[
...getPrivateChatCommands(DEFAULT_LANGUAGE_CODE),
...getPrivateChatAdminCommands(DEFAULT_LANGUAGE_CODE),
// ...(isMultipleLocales ? [getLanguageCommand(DEFAULT_LANGUAGE_CODE)] : []),
...getPrivateChatCommands(),
...getPrivateChatAdminCommands(),
],
{
scope: {
Expand Down
2 changes: 1 addition & 1 deletion src/bot/handlers/error.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ErrorHandler } from 'grammy'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'
import { getUpdateInfo } from '#root/bot/helpers/logging.js'

export const errorHandler: ErrorHandler<Context> = (error) => {
Expand Down
2 changes: 1 addition & 1 deletion src/bot/helpers/logging.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Middleware } from 'grammy'
import type { Update } from '@grammyjs/types'
import type { Context } from '#root/bot/context.js'
import type { Context } from '#root/bot/grammy-context.js'

export function getUpdateInfo(ctx: Context): Omit<Update, 'update_id'> {
const { update_id, ...update } = ctx.update
Expand Down
20 changes: 8 additions & 12 deletions src/bot/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

import type { BotConfig, StorageAdapter } from 'grammy'
import { Bot as TelegramBot, Api } from 'grammy'
import type { Context, SessionData } from '#root/bot/context.js'
import { createContextConstructor } from '#root/bot/context.js'
import type { Context, SessionData } from '#root/bot/grammy-context.js'
import { createContextConstructor } from '#root/bot/grammy-context.js'
import type { Logger } from '#root/logger.js'
import { Context as UbiquityOsContext } from '../types'
import { welcomeFeature } from '#root/bot/features/welcome.js'
Expand All @@ -12,11 +12,10 @@ import { session } from '#root/bot/middlewares/session.js'
import { autoChatAction } from '@grammyjs/auto-chat-action'
import { hydrate } from '@grammyjs/hydrate'
import { hydrateReply, parseMode } from '@grammyjs/parse-mode'
import { i18n } from './i18n'
import { adminFeature } from './features/admin/admin'
import { userIdFeature } from './features/helpers/user-id'
import { createForumsFeature } from './features/on/forum-created'
import { chatIdFeature } from './features/helpers/chatid'
import { userIdFeature } from './features/commands/user-id'
import { chatIdFeature } from './features/commands/chat-id'
import { botIdFeature } from './features/commands/bot-id'

interface Dependencies {
config: UbiquityOsContext["env"]
Expand Down Expand Up @@ -47,24 +46,21 @@ export function createBot(token: string, dependencies: Dependencies, options: Op
})
const protectedBot = bot.errorBoundary(errorHandler)

// // createForumsFeature
bot.api.config.use(parseMode('HTML'))

protectedBot.use(autoChatAction(bot.api))
protectedBot.use(hydrateReply)
protectedBot.use(hydrate())
protectedBot.use(session({ getSessionKey, storage: options.botSessionStorage }))

// // Handlers
// Handlers
protectedBot.use(welcomeFeature)
protectedBot.use(adminFeature)
protectedBot.use(userIdFeature)
protectedBot.use(chatIdFeature)
// protectedBot.use(createForumsFeature)
// if (isMultipleLocales)
// protectedBot.use(languageFeature)
protectedBot.use(botIdFeature)

// // must be the last handler
// must be the last handler
protectedBot.use(unhandledFeature)

return bot
Expand Down
2 changes: 1 addition & 1 deletion src/bot/middlewares/session.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Middleware, type SessionOptions, session as createSession } from 'grammy'
import type { Context, SessionData } from '#root/bot/context.js'
import type { Context, SessionData } from '#root/bot/grammy-context.js'

type Options = Pick<SessionOptions<SessionData, Context>, 'getSessionKey' | 'storage'>

Expand Down
73 changes: 38 additions & 35 deletions src/handlers/callbacks-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
import { createChat } from "#root/bot/workflow-functions/create-chat.js";
import { ProxyCallbacks } from "#root/types/proxy.js";
import { Context, SupportedEventsU } from "../types";
import { createChat } from "../workflow-functions/create-chat";
import { closeWorkroom, createWorkroom, reOpenWorkroom } from "./github/workrooms";

/**
* Why do we need this wrapper function?
*
* By using a generic `Function` type for the callback parameter, we bypass strict type
* checking temporarily. This allows us to pass a standard `Context` object, which we know
* contains the correct event and payload types, to the callback safely.
*
* We can trust that the `ProxyCallbacks` type has already ensured that each callback function
* matches the expected event and payload types, so this function provides a safe and
* flexible way to handle callbacks without introducing type or logic errors.
*/
function handleCallback(callback: Function, context: Context) {
return callback(context);
}
/**
* The `callbacks` object defines an array of callback functions for each supported event type.
*
Expand All @@ -36,6 +22,28 @@ const callbacks = {
]
} as ProxyCallbacks;


/**
* These are function which get dispatched by this worker to fire off workflows
* in the repository. We enter through the main `compute.yml` just like a typical
* action plugin would, we forward the same payload that the worker received to
* the workflow the same way that the kernel does.
*
* - First event fires, `issues.labeled` and the worker catches it.
* - The worker then dispatches a workflow to `compute.yml` with the event name as the input.
* - The workflow receives a `issues.labeled` payload but eventName is now WorkflowFunction (`create-telegram-chat`).
* - The workflow then runs the `createChat` function which needs a node env to run.
*
* I.e we're essentially running the first dual action/worker plugin which is
* ideal for telegram-bot as it's a bot that needs to be able to be super flexible.
*/
const workflowCallbacks = {
"issues.labeled": [
createChat
]
} as ProxyCallbacks;


/**
* The `proxyCallbacks` function returns a Proxy object that intercepts access to the
* `callbacks` object. This Proxy enables dynamic handling of event callbacks, including:
Expand Down Expand Up @@ -71,26 +79,6 @@ export function proxyCallbacks(context: Context): ProxyCallbacks {
});
}

/**
* These are function which get dispatched by this worker to fire off workflows
* in the repository. We enter through the main `compute.yml` just like a typical
* action plugin would, we forward the same payload that the worker received to
* the workflow the same way that the kernel does.
*
* - First event fires, `issues.labeled` and the worker catches it.
* - The worker then dispatches a workflow to `compute.yml` with the event name as the input.
* - The workflow receives a `issues.labeled` payload but eventName is now WorkflowFunction (`create-telegram-chat`).
* - The workflow then runs the `createChat` function which needs a node env to run.
*
* I.e we're essentially running the first dual action/worker plugin which is
* ideal for telegram-bot as it's a bot that needs to be able to be super flexible.
*/
const workflowCallbacks = {
"issues.labeled": [
createChat
]
} as ProxyCallbacks;


export function proxyWorkflowCallbacks(context: Context): ProxyCallbacks {
return new Proxy(workflowCallbacks, {
Expand All @@ -109,4 +97,19 @@ export function proxyWorkflowCallbacks(context: Context): ProxyCallbacks {
})();
},
});
}

/**
* Why do we need this wrapper function?
*
* By using a generic `Function` type for the callback parameter, we bypass strict type
* checking temporarily. This allows us to pass a standard `Context` object, which we know
* contains the correct event and payload types, to the callback safely.
*
* We can trust that the `ProxyCallbacks` type has already ensured that each callback function
* matches the expected event and payload types, so this function provides a safe and
* flexible way to handle callbacks without introducing type or logic errors.
*/
function handleCallback(callback: Function, context: Context) {
return callback(context);
}
23 changes: 9 additions & 14 deletions src/handlers/github/workrooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,23 @@ import { CallbackResult } from "#root/types/proxy.js";
import { TelegramBotSingleton } from "#root/utils/telegram-bot-single.js";
import { Context, SupportedEvents } from "../../types";
import { repositoryDispatch } from "../repository-dispatch";
import { addCommentToIssue } from "./utils/add-comment-to-issues";
import { addCommentToIssue } from "../../helpers/add-comment-to-issues";

/**
* V1 specifications for the `workrooms` feature.
*
* - A workroom is created when an issue is labeled.
* - The workroom is created in a Telegram supergroup as a forum topic, not a new group.
* - The workroom is associated with the issue by storing the issue's node_id.
* - The workroom is closed when the issue is closed.
* - The workroom status is updated to "closed" in the database.
* - A comment is added to the issue when the workroom is created or closed.
*
* V2 specifications:
*
* - Replace the `Bot` api with the `MTProto` api in order to create new group chats.
* Dispatches a workflow in order to use the MTProto API to create a new chat
* for the task.
*/

export async function createWorkroom(context: Context<"issues.labeled", SupportedEvents["issues.labeled"]>): Promise<CallbackResult> {
await repositoryDispatch(context, "create-telegram-chat").catch(console.error);
return { status: 200, reason: "workflow_dispatched" };
}

/**
* "Closes" the workroom by kicking all users from the chat and archiving it.
*
* - Does not delete the chat as it is required for later use.
* - Does not require MTProto API as we'll use the Bot API to kick users.
*/
export async function closeWorkroom(context: Context<"issues.closed", SupportedEvents["issues.closed"]>): Promise<CallbackResult> {
const { logger, config, adapters: { supabase: { chats } } } = context;
const bot = TelegramBotSingleton.getInstance().getBot();
Expand Down
Loading

0 comments on commit fbe8e79

Please sign in to comment.