Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions bot/modules/community/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ const getVolumeNDays = async (

export const onCommunityInfo = async (ctx: MainContext) => {
const commId = ctx.match?.[1];
const community = await Community.findById(commId);
const community = await Community.findOne({
_id: commId,
enabled: { $ne: false },
});
if (community === null) throw new Error('community not found');
const userCount = await User.countDocuments({ default_community_id: commId });
const orderCount = await getOrdersNDays(1, commId);
Expand Down Expand Up @@ -120,7 +123,13 @@ export const onSetCommunity = async (ctx: CommunityContext) => {

export const withdrawEarnings = async (ctx: CommunityContext) => {
ctx.deleteMessage();
const community = await Community.findById(ctx.match?.[1]);
const community = await Community.findOne({
_id: ctx.match?.[1],
enabled: { $ne: false },
});
if (community == null) {
return ctx.reply(ctx.i18n.t('community_not_found'));
}
ctx.scene.enter('ADD_EARNINGS_INVOICE_WIZARD_SCENE_ID', {
community,
});
Comment thread
Matobi98 marked this conversation as resolved.
Expand Down
166 changes: 161 additions & 5 deletions bot/modules/community/commands.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/* 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';
import { Telegraf } from 'telegraf';
import { getUserI18nContext } from '../../../util';

async function getOrderCountByCommunity(): Promise<number[]> {
const data = await Order.aggregate([
Expand All @@ -21,6 +22,7 @@ async function findCommunities(currency: string) {
const communities = await Community.find({
currencies: currency,
public: true,
enabled: { $ne: false },
});
const orderCount = await getOrderCountByCommunity();
return communities.map(comm => {
Expand Down Expand Up @@ -49,9 +51,15 @@ export const setComm = async (ctx: MainContext) => {
if (groupName[0] == '@') {
// Allow find communities case insensitive
const regex = new RegExp(['^', groupName, '$'].join(''), 'i');
community = await Community.findOne({ group: regex });
community = await Community.findOne({
group: regex,
enabled: { $ne: false },
});
} else if (groupName[0] == '-') {
community = await Community.findOne({ group: groupName });
community = await Community.findOne({
group: groupName,
enabled: { $ne: false },
});
}
if (!community) {
return await ctx.reply(ctx.i18n.t('community_not_found'));
Expand All @@ -70,7 +78,11 @@ export const communityAdmin = async (ctx: CommunityContext) => {
try {
const [group] = (await validateParams(ctx, 2, '\\<_community_\\>'))!;
const creator_id = ctx.user.id;
const [community] = await Community.find({ group, creator_id });
const [community] = await Community.find({
group,
creator_id,
enabled: { $ne: false },
});
if (!community) throw new Error('CommunityNotFound');
await ctx.scene.enter('COMMUNITY_ADMIN', { community });
} catch (err: any) {
Expand All @@ -89,7 +101,10 @@ export const myComms = async (ctx: MainContext) => {
try {
const { user } = ctx;

const communities = await Community.find({ creator_id: user._id });
const communities = await Community.find({
creator_id: user._id,
enabled: { $ne: false },
});

if (!communities.length)
return await ctx.reply(ctx.i18n.t('you_dont_have_communities'));
Expand Down Expand Up @@ -147,6 +162,7 @@ export const updateCommunity = async (
const community = await Community.findOne({
_id: id,
creator_id: user._id,
enabled: { $ne: false },
});

if (!community) {
Expand Down Expand Up @@ -228,6 +244,7 @@ export const deleteCommunity = async (ctx: CommunityContext) => {
const community = await Community.findOne({
_id: id,
creator_id: ctx.user._id,
enabled: { $ne: false },
});

if (!community) {
Expand All @@ -241,6 +258,144 @@ export const deleteCommunity = async (ctx: CommunityContext) => {
}
};

async function findCommunityByInput(
ctx: MainContext,
input: string,
): Promise<typeof Community.prototype | null> {
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 null;
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 === 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 {
const creatorI18n = await getUserI18nContext(creator);
await ctx.telegram.sendMessage(
creator.tg_id,
creatorI18n.t('community_disabled_by_admin', {
communityName: community.name,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This notification is sent with the superadmin locale (superAdminMiddleware sets ctx.i18n from the admin). The creator will receive the DM in the wrong language whenever admin and creator locales differ. Please localize it for the creator or send a neutral message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — disableCommunity and enableCommunity now call getUserI18nContext(creator) to get the creator's own locale before sending the DM, instead of using ctx.i18n which carries the superadmin's locale.

}),
);
} 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 === 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 {
const creatorI18n = await getUserI18nContext(creator);
await ctx.telegram.sendMessage(
creator.tg_id,
creatorI18n.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();
Expand All @@ -251,6 +406,7 @@ export const changeVisibility = async (ctx: CommunityContext) => {
const community = await Community.findOne({
_id: id,
creator_id: ctx.user._id,
enabled: { $ne: false },
});

if (!community) {
Expand Down
13 changes: 12 additions & 1 deletion bot/modules/community/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Telegraf } from 'telegraf';
import { userMiddleware } from '../../middleware/user';
import { userMiddleware, superAdminMiddleware } from '../../middleware/user';
import * as actions from './actions';
import * as commands from './commands';
import {
Expand Down Expand Up @@ -65,6 +65,17 @@ export const configure = (bot: Telegraf<CommunityContext>) => {
},
);

bot.command(
'disablecommunity',
superAdminMiddleware,
commands.disableCommunity,
);
bot.command(
'enablecommunity',
superAdminMiddleware,
commands.enableCommunity,
);

bot.command('findcomms', userMiddleware, commands.findCommunity);
bot.action(
/^communityInfo_([0-9a-f]{24})$/,
Expand Down
10 changes: 8 additions & 2 deletions bot/modules/community/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ export const updateCommunityMessage = async (ctx: MainContext) => {
try {
await ctx.deleteMessage();
const id = ctx.match?.[1];
const community = await Community.findById(id);
const community = await Community.findOne({
_id: id,
enabled: { $ne: false },
});
if (community == null) throw new Error('community was not found');
let text = ctx.i18n.t('community') + `: ${community.name}\n`;
text += ctx.i18n.t('what_to_do');
Expand Down Expand Up @@ -170,7 +173,10 @@ export const earningsMessage = async (ctx: MainContext) => {
if (isScheduled)
return await ctx.reply(ctx.i18n.t('invoice_already_being_paid'));

const community = await Community.findById(communityId);
const community = await Community.findOne({
_id: communityId,
enabled: { $ne: false },
});
if (community == null) throw new Error('community was not found');
const button =
community.earnings > 0
Expand Down
Loading
Loading