From b9b6baa7868ec17450d6daea77ea3f9b1a7eb3f9 Mon Sep 17 00:00:00 2001 From: Maxi Vila Date: Wed, 20 May 2026 21:36:15 -0300 Subject: [PATCH 1/4] feat: re-enable community creation via COMMUNITY_CREATION_ENABLED env var --- .env-sample | 4 ++++ bot/modules/community/index.ts | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.env-sample b/.env-sample index 009fda2f..c00f4a2e 100644 --- a/.env-sample +++ b/.env-sample @@ -111,3 +111,7 @@ MONITOR_URL='' MONITOR_AUTH_TOKEN='' # Bot name identifier sent with heartbeats (default: lnp2pBot) MONITOR_BOT_NAME='lnp2pBot' + +# Set to 'true' to enable the /community command, allowing users to create new communities. +# Default is false (disabled) so bot operators can run closed instances without exposing community creation. +COMMUNITY_CREATION_ENABLED=false diff --git a/bot/modules/community/index.ts b/bot/modules/community/index.ts index e9ac6da4..f18507e3 100644 --- a/bot/modules/community/index.ts +++ b/bot/modules/community/index.ts @@ -13,11 +13,11 @@ import * as Scenes from './scenes'; export const configure = (bot: Telegraf) => { bot.command('mycomm', userMiddleware, commands.communityAdmin); bot.command('mycomms', userMiddleware, commands.myComms); - // TODO: Uncomment when the community wizard is ready - // bot.command('community', userMiddleware, async ctx => { - // const { user } = ctx; - // await ctx.scene.enter('COMMUNITY_WIZARD_SCENE_ID', { bot, user }); - // }); + if (process.env.COMMUNITY_CREATION_ENABLED === 'true') { + bot.command('community', userMiddleware, async ctx => { + await ctx.scene.enter('COMMUNITY_WIZARD_SCENE_ID', { bot, user: ctx.user }); + }); + } bot.command('setcomm', userMiddleware, commands.setComm); bot.action( From 2ec02e467d4d4f3f41ae8029682beac23cec6a72 Mon Sep 17 00:00:00 2001 From: Maxi Vila Date: Wed, 20 May 2026 21:36:47 -0300 Subject: [PATCH 2/4] style: apply prettier formatting to community index --- bot/modules/community/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bot/modules/community/index.ts b/bot/modules/community/index.ts index f18507e3..f9282a0c 100644 --- a/bot/modules/community/index.ts +++ b/bot/modules/community/index.ts @@ -15,7 +15,10 @@ export const configure = (bot: Telegraf) => { bot.command('mycomms', userMiddleware, commands.myComms); if (process.env.COMMUNITY_CREATION_ENABLED === 'true') { bot.command('community', userMiddleware, async ctx => { - await ctx.scene.enter('COMMUNITY_WIZARD_SCENE_ID', { bot, user: ctx.user }); + await ctx.scene.enter('COMMUNITY_WIZARD_SCENE_ID', { + bot, + user: ctx.user, + }); }); } bot.command('setcomm', userMiddleware, commands.setComm); From 5b0a9e0e34156971afc904818c019f7dbeddfe10 Mon Sep 17 00:00:00 2001 From: Maxi Vila Date: Wed, 20 May 2026 21:47:49 -0300 Subject: [PATCH 3/4] fix: avoid duplicate replies on invalid community ID in disable/enable commands --- bot/modules/community/commands.ts | 138 ++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/bot/modules/community/commands.ts b/bot/modules/community/commands.ts index 78e60525..d04697de 100644 --- a/bot/modules/community/commands.ts +++ b/bot/modules/community/commands.ts @@ -241,6 +241,144 @@ export const deleteCommunity = async (ctx: CommunityContext) => { } }; +async function findCommunityByInput( + ctx: MainContext, + input: string, +): Promise { + if (input[0] === '@') { + const escapedInput = input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regex = new RegExp(`^${escapedInput}$`, 'i'); + return Community.findOne({ group: regex }); + } + if (!(await validateObjectId(ctx, input))) return undefined; + return Community.findOne({ _id: input }); +} + +function buildCommunityInfoText( + ctx: MainContext, + community: typeof Community.prototype, + creatorUsername: string, + localeKey: string, +): string { + const solversText = + community.solvers.length > 0 + ? community.solvers + .map((s: { username: string }) => `@${s.username}`) + .join(', ') + : '-'; + const groupText = community.group || '-'; + return ctx.i18n.t(localeKey, { + communityName: community.name, + group: groupText, + solvers: solversText, + creatorUsername, + }); +} + +export const disableCommunity = async (ctx: MainContext) => { + try { + const [input] = (await validateParams( + ctx, + 2, + '\\<_community id \\| @groupUsername_\\>', + ))!; + if (!input) return; + + const community = await findCommunityByInput(ctx, input); + if (community === undefined) return; + if (community === null) { + return ctx.reply(ctx.i18n.t('community_not_found')); + } + + if (community.enabled === false) { + return ctx.reply(ctx.i18n.t('community_already_disabled')); + } + + community.enabled = false; + await community.save(); + + const creator = await User.findById(community.creator_id); + const creatorUsername = creator?.username || 'unknown'; + + if (creator) { + try { + await ctx.telegram.sendMessage( + creator.tg_id, + ctx.i18n.t('community_disabled_by_admin', { + communityName: community.name, + }), + ); + } catch (notifyError) { + logger.error(notifyError); + } + } + + return ctx.reply( + buildCommunityInfoText( + ctx, + community, + creatorUsername, + 'community_disabled_info', + ), + ); + } catch (error) { + logger.error(error); + await ctx.reply(ctx.i18n.t('generic_error')); + } +}; + +export const enableCommunity = async (ctx: MainContext) => { + try { + const [input] = (await validateParams( + ctx, + 2, + '\\<_community id \\| @groupUsername_\\>', + ))!; + if (!input) return; + + const community = await findCommunityByInput(ctx, input); + if (community === undefined) return; + if (community === null) { + return ctx.reply(ctx.i18n.t('community_not_found')); + } + + if (community.enabled !== false) { + return ctx.reply(ctx.i18n.t('community_already_enabled')); + } + + community.enabled = true; + await community.save(); + + const creator = await User.findById(community.creator_id); + const creatorUsername = creator?.username || 'unknown'; + + if (creator) { + try { + await ctx.telegram.sendMessage( + creator.tg_id, + ctx.i18n.t('community_enabled_by_admin', { + communityName: community.name, + }), + ); + } catch (notifyError) { + logger.error(notifyError); + } + } + + return ctx.reply( + buildCommunityInfoText( + ctx, + community, + creatorUsername, + 'community_enabled_info', + ), + ); + } catch (error) { + logger.error(error); + await ctx.reply(ctx.i18n.t('generic_error')); + } +}; + export const changeVisibility = async (ctx: CommunityContext) => { try { ctx.deleteMessage(); From 2165f9fe5208001e648b999d13ace8067393d34e Mon Sep 17 00:00:00 2001 From: Maxi Vila Date: Thu, 21 May 2026 13:49:25 -0300 Subject: [PATCH 4/4] fix: add missing User import in community commands after rebase --- bot/modules/community/commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/modules/community/commands.ts b/bot/modules/community/commands.ts index d04697de..ede199f4 100644 --- a/bot/modules/community/commands.ts +++ b/bot/modules/community/commands.ts @@ -1,7 +1,7 @@ /* eslint-disable no-underscore-dangle */ import { logger } from '../../../logger'; import { showUserCommunitiesMessage } from './messages'; -import { Community, Order } from '../../../models'; +import { Community, Order, User } from '../../../models'; import { validateParams, validateObjectId } from '../../validations'; import { MainContext } from '../../start'; import { CommunityContext } from './communityContext';