Skip to content
Open
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: 13 additions & 0 deletions bot/modules/community/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export const onCommunityInfo = async (ctx: MainContext) => {
const commId = ctx.match?.[1];
const community = await Community.findById(commId);
if (community === null) throw new Error('community not found');
if (!community.active) {
return await ctx.reply(ctx.i18n.t('community_inactive'));
}
const userCount = await User.count({ default_community_id: commId });
const orderCount = await getOrdersNDays(1, commId);
const volume = await getVolumeNDays(1, commId);
Expand Down Expand Up @@ -111,6 +114,13 @@ export const onCommunityInfo = async (ctx: MainContext) => {
export const onSetCommunity = async (ctx: CommunityContext) => {
const tgId = (ctx.update as any).callback_query.from.id;
const defaultCommunityId = ctx.match?.[1];

// Check if the community is active before setting it as default
const community = await Community.findById(defaultCommunityId);
if (!community || !community.active) {
return await ctx.reply(ctx.i18n.t('community_inactive'));
}

await User.findOneAndUpdate(
{ tg_id: tgId },
{ default_community_id: defaultCommunityId },
Expand All @@ -121,6 +131,9 @@ export const onSetCommunity = async (ctx: CommunityContext) => {
export const withdrawEarnings = async (ctx: CommunityContext) => {
ctx.deleteMessage();
const community = await Community.findById(ctx.match?.[1]);
if (!community || !community.active) {
return await ctx.reply(ctx.i18n.t('community_inactive'));
}
ctx.scene.enter('ADD_EARNINGS_INVOICE_WIZARD_SCENE_ID', {
community,
});
Expand Down
9 changes: 7 additions & 2 deletions bot/modules/community/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async function findCommunities(currency: string) {
const communities = await Community.find({
currencies: currency,
public: true,
active: true,
});
const orderCount = await getOrderCountByCommunity();
return communities.map(comm => {
Expand Down Expand Up @@ -49,9 +50,9 @@ 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, active: true });
} else if (groupName[0] == '-') {
community = await Community.findOne({ group: groupName });
community = await Community.findOne({ group: groupName, active: true });
}
Comment on lines +53 to 56
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Differentiate “not found” vs “inactive” on /setcomm

Right now inactive communities fall through as “not found”. Prefer explicit feedback using community_inactive.

-      const regex = new RegExp(['^', groupName, '$'].join(''), 'i');
-      community = await Community.findOne({ group: regex, active: true });
+      const regex = new RegExp(['^', groupName, '$'].join(''), 'i');
+      community = await Community.findOne({ group: regex });
+      if (community && !community.active) {
+        return await ctx.reply(ctx.i18n.t('community_inactive'));
+      }
     } else if (groupName[0] == '-') {
-      community = await Community.findOne({ group: groupName, active: true });
+      community = await Community.findOne({ group: groupName });
+      if (community && !community.active) {
+        return await ctx.reply(ctx.i18n.t('community_inactive'));
+      }
     }
-    if (!community) {
+    if (!community) {
       return await ctx.reply(ctx.i18n.t('community_not_found'));
     }

Also applies to: 57-59

🤖 Prompt for AI Agents
In bot/modules/community/commands.ts around lines 53-56 (and similarly at
57-59), the current logic treats inactive communities as "not found" because it
only queries for active: true; change each lookup to first fetch the community
regardless of active status (remove active filter), then check community.exists:
if not found return community_not_found; else if community.active is false
return community_inactive; otherwise proceed as before. Apply this pattern to
both the regex lookup and the groupName ('-'-prefixed) lookup (and the
subsequent similar block at 57-59).

if (!community) {
return await ctx.reply(ctx.i18n.t('community_not_found'));
Expand All @@ -70,6 +71,7 @@ export const communityAdmin = async (ctx: CommunityContext) => {
try {
const [group] = (await validateParams(ctx, 2, '\\<_community_\\>'))!;
const creator_id = ctx.user.id;
// Allow creators to access admin panel even for inactive communities
const [community] = await Community.find({ group, creator_id });
if (!community) throw new Error('CommunityNotFound');
await ctx.scene.enter('COMMUNITY_ADMIN', { community });
Expand Down Expand Up @@ -144,6 +146,7 @@ export const updateCommunity = async (
const { user } = ctx;

if (!(await validateObjectId(ctx, id))) return;
// Allow admin to update even inactive communities
const community = await Community.findOne({
_id: id,
creator_id: user._id,
Expand Down Expand Up @@ -213,6 +216,7 @@ export const deleteCommunity = async (ctx: CommunityContext) => {
if (id === undefined) throw new Error('id is undefined');

if (!(await validateObjectId(ctx, id))) return;
// Allow admin to delete even inactive communities
const community = await Community.findOne({
_id: id,
creator_id: ctx.user._id,
Expand All @@ -236,6 +240,7 @@ export const changeVisibility = async (ctx: CommunityContext) => {
if (id === undefined) throw new Error('id is undefined');

if (!(await validateObjectId(ctx, id))) return;
// Allow admin to change visibility even for inactive communities
const community = await Community.findOne({
_id: id,
creator_id: ctx.user._id,
Expand Down
9 changes: 7 additions & 2 deletions bot/modules/user/scenes/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ function make() {
};
if (user.default_community_id) {
const community = await Community.findById(user.default_community_id);
if (community == null) throw new Error('community not found');
data.community = community.group;
// If default community exists but is inactive, clear it
if (community && !community.active) {
user.default_community_id = undefined;
await user.save();
} else if (community) {
data.community = community.group;
}
}
if (user.nostr_public_key) {
data.npub = NostrLib.encodeNpub(user.nostr_public_key);
Expand Down
9 changes: 4 additions & 5 deletions bot/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import {
deleteOrders,
calculateEarnings,
attemptCommunitiesPendingPayments,
// deleteCommunity,
disableCommunity,
nodeInfo,
checkSolvers,
} from '../jobs';
Expand Down Expand Up @@ -222,10 +222,9 @@ const initialize = (
await attemptCommunitiesPendingPayments(bot);
});

// TODO: re-enable later
// schedule.scheduleJob(`33 0 * * *`, async () => {
// await deleteCommunity(bot);
// });
schedule.scheduleJob(`33 0 * * *`, async () => {
await disableCommunity(bot);
});

schedule.scheduleJob(`* * * * *`, async () => {
await nodeInfo(bot);
Expand Down
14 changes: 12 additions & 2 deletions bot/validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,15 @@ const validateAdmin = async (ctx: MainContext, id?: string) => {
if (user === null) return;

let community = null;
if (user.default_community_id)
if (user.default_community_id) {
community = await Community.findOne({ _id: user.default_community_id });
// If default community exists but is inactive, clear it
if (community && !community.active) {
user.default_community_id = undefined;
await user.save();
community = null;
}
}

const isSolver = isDisputeSolver(community, user);

Expand Down Expand Up @@ -730,7 +737,10 @@ const isBannedFromCommunity = async (
) => {
try {
if (!communityId) return false;
const community = await Community.findOne({ _id: communityId });
const community = await Community.findOne({
_id: communityId,
active: true,
});
if (!community) return false;
return community.banned_users.some(
(buser: IUsernameId) => buser.id == user._id,
Expand Down
5 changes: 3 additions & 2 deletions jobs/check_solvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ const notifyAdmin = async (
* The community is disabled if the admin has received the maximum notification message (MAX_ADMIN_WARNINGS_BEFORE_DEACTIVATION - 1) to add a solver.
*/
if (community.warning_messages_count >= maxWarningsCount) {
await community.delete();
community.active = false;
await community.save();

logger.info(
`Community: ${community.name} has been deleted due to lack of solvers.`,
`Community: ${community.name} has been deactivated due to lack of solvers.`,
);
return;
}
Expand Down
17 changes: 13 additions & 4 deletions jobs/communities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Order, Community } from '../models';
import { logger } from '../logger';
import { CommunityContext } from '../bot/modules/community/communityContext';

const deleteCommunity = async (bot: Telegraf<CommunityContext>) => {
const disableCommunity = async (bot: Telegraf<CommunityContext>) => {
try {
const communities = await Community.find();
for (const community of communities) {
Expand All @@ -25,13 +25,22 @@ const deleteCommunity = async (bot: Telegraf<CommunityContext>) => {
logger.info(
`Community: ${community.name} have ${process.env.COMMUNITY_TTL} days without a successfully completed order, it's being deleted!`,
);
await community.delete();
community.active = false;
await community.save();
// Notify the community admin
const admin = await bot.telegram.getChat(community.creator_id);
if (admin) {
await bot.telegram.sendMessage(
admin.id,
`Your community ${community.name} has been deactivated due to inactivity. Please contact support if you have any questions.`,
);
}
}
}
} catch (error) {
const message = String(error);
logger.error(`deleteCommunity catch error: ${message}`);
logger.error(`disableCommunity catch error: ${message}`);
}
};

export default deleteCommunity;
export default disableCommunity;
4 changes: 2 additions & 2 deletions jobs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import cancelOrders from './cancel_orders';
import deleteOrders from './delete_published_orders';
import calculateEarnings from './calculate_community_earnings';
import deleteCommunity from './communities';
import disableCommunity from './communities';
import nodeInfo from './node_info';
import checkSolvers from './check_solvers';

Expand All @@ -15,7 +15,7 @@ export {
deleteOrders,
calculateEarnings,
attemptCommunitiesPendingPayments,
deleteCommunity,
disableCommunity,
nodeInfo,
checkSolvers,
};
1 change: 1 addition & 0 deletions locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ channels: Kanäle
dispute_solvers: Streitschlichter
no_default_community: Du hast keine standardmäßige Community mehr
community_not_found: Community nicht gefunden
community_inactive: Diese Community ist derzeit inaktiv und kann nicht für den Handel verwendet werden
currency: Währung
currencies: Währungen
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ channels: Channels
dispute_solvers: Solvers
no_default_community: You no longer have a community by default
community_not_found: Community not found
community_inactive: This community is currently inactive and cannot be used for trading
currency: Currency
currencies: Currencies
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/es.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ channels: Canales
dispute_solvers: Solvers
no_default_community: Ya no tienes comunidad por defecto
community_not_found: Comunidad no encontrada
community_inactive: Esta comunidad está actualmente inactiva y no puede ser usada para operaciones
currency: Moneda
currencies: Monedas
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/fa.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ channels: کانال‌ها
dispute_solvers: حل کننده‌ها
no_default_community: شما دیگر به صورت پیش فرض کامیونیتی ندارید
community_not_found: کامیونیتی پیدا نشد
community_inactive: این کامیونیتی در حال حاضر غیرفعال است و نمی‌تواند برای معاملات استفاده شود
currency: ارز
currencies: ارزها
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/fr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ channels: Canaux
dispute_solvers: Mediateurs
no_default_community: Vous n'avez plus de communauté par défaut
community_not_found: Communauté non trouvée
community_inactive: Cette communauté est actuellement inactive et ne peut pas être utilisée pour le commerce
currency: Devise
currencies: Devises
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/it.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ channels: Canali
dispute_solvers: Arbitri
no_default_community: Non hai più una comunità di default
community_not_found: Community non trovata
community_inactive: Questa community è attualmente inattiva e non può essere utilizzata per il commercio
currency: Valuta
currencies: Valute
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/ko.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ channels: 채널들
dispute_solvers: 분쟁 해결자들
no_default_community: 기본적으로 당신은 속한 커뮤니티가 없습니다.
community_not_found: 커뮤니티를 찾을 수 없습니다.
community_inactive: 이 커뮤니티는 현재 비활성 상태이며 거래에 사용할 수 없습니다
currency: 통화
currencies: 통화들
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/pt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ channels: Canais
dispute_solvers: Solucionadores
no_default_community: Você não tem mais uma comunidade por padrão
community_not_found: Comunidade não encontrada
community_inactive: Esta comunidade está atualmente inativa e não pode ser usada para negociação
currency: Moeda
currencies: Moedas
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/ru.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ channels: Channels
dispute_solvers: Solvers
no_default_community: You no longer have a community by default
community_not_found: Community not found
community_inactive: Это сообщество в настоящее время неактивно и не может быть использовано для торговли
currency: Валюта
currencies: Currencies
currency_not_supported: |
Expand Down
1 change: 1 addition & 0 deletions locales/uk.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ channels: Канали
dispute_solvers: Вирішення
no_default_community: У вас більше немає спільноти за замовчуванням
community_not_found: Спільнота не знайдено
community_inactive: Ця спільнота зараз неактивна і не може використовуватися для торгівлі
currency: Валюта
currencies: Валюти
currency_not_supported: |
Expand Down
2 changes: 2 additions & 0 deletions models/community.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface ICommunity extends Document {
solvers: Types.DocumentArray<IUsernameId>;
banned_users: Types.DocumentArray<IUsernameId>;
public: boolean;
active: boolean;
currencies: Array<string>;
created_at: Date;
nostr_public_key: string;
Expand Down Expand Up @@ -73,6 +74,7 @@ const CommunitySchema = new Schema<ICommunity>({
solvers: [usernameIdSchema], // users that are dispute solvers
banned_users: [usernameIdSchema], // users that are banned from the community
public: { type: Boolean, default: true },
active: { type: Boolean, default: true },
currencies: {
type: [String],
required: true,
Expand Down
4 changes: 3 additions & 1 deletion models/indexes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ const createIndexSafely = async (

if (indexExists) {
logger.info(
`Index on ${JSON.stringify(indexSpec)} already exists in ${collectionName} collection`,
`Index on ${JSON.stringify(
indexSpec,
)} already exists in ${collectionName} collection`,
);
return;
}
Expand Down
7 changes: 4 additions & 3 deletions util/communityHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const getCommunityInfo = async (
if (chatType !== 'private' && chat?.username) {
// Group chat - find community by group name
const regex = new RegExp(`^@${chat.username}$`, 'i');
community = await Community.findOne({ group: regex });
community = await Community.findOne({ group: regex, active: true });
if (community) {
communityId = community._id;
}
Expand All @@ -36,11 +36,12 @@ export const getCommunityInfo = async (
communityId = user.default_community_id;
community = await Community.findById(communityId);

// If community not found, clear the user's default
if (!community) {
// If community not found or inactive, clear the user's default
if (!community || !community.active) {
user.default_community_id = undefined;
await user.save();
communityId = undefined;
community = null;
}
}

Expand Down
17 changes: 13 additions & 4 deletions util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,10 @@ const deleteOrderFromChannel = async (order: IOrder, telegram: Telegram) => {
try {
let channel = process.env.CHANNEL;
if (order.community_id) {
const community = await Community.findOne({ _id: order.community_id });
const community = await Community.findOne({
_id: order.community_id,
active: true,
});
if (!community) {
return channel;
}
Expand All @@ -321,7 +324,10 @@ const deleteOrderFromChannel = async (order: IOrder, telegram: Telegram) => {
const getOrderChannel = async (order: IOrder) => {
let channel = process.env.CHANNEL;
if (order.community_id) {
const community = await Community.findOne({ _id: order.community_id });
const community = await Community.findOne({
_id: order.community_id,
active: true,
});
if (!community) {
return channel;
}
Expand All @@ -342,7 +348,10 @@ const getOrderChannel = async (order: IOrder) => {
const getDisputeChannel = async (order: IOrder) => {
let channel = process.env.DISPUTE_CHANNEL;
if (order.community_id) {
const community = await Community.findOne({ _id: order.community_id });
const community = await Community.findOne({
_id: order.community_id,
active: true,
});
if (community === null) throw Error('Community was not found in DB');
channel = community.dispute_channel;
}
Expand Down Expand Up @@ -454,7 +463,7 @@ const getFee = async (
// Calculate fees
const botFee = maxFee * Number(process.env.FEE_PERCENT);
let communityFee = Math.round(maxFee - botFee);
const community = await Community.findOne({ _id: communityId });
const community = await Community.findOne({ _id: communityId, active: true });
if (community === null) throw Error('Community was not found in DB');
communityFee = communityFee * (community.fee / 100);

Comment on lines +466 to 469
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fee calc should treat inactive as “no community” instead of throwing.

Throwing propagates to order flows. Return the global-fee path when inactive/missing.

-  const community = await Community.findOne({ _id: communityId, active: true });
-  if (community === null) throw Error('Community was not found in DB');
-  communityFee = communityFee * (community.fee / 100);
+  const community = await Community.findOne({ _id: communityId, active: true });
+  if (!community) {
+    return isGoldenHoneyBadger ? 0 : maxFee;
+  }
+  communityFee = communityFee * (community.fee / 100);

Run: npm run format

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const community = await Community.findOne({ _id: communityId, active: true });
if (community === null) throw Error('Community was not found in DB');
communityFee = communityFee * (community.fee / 100);
const community = await Community.findOne({ _id: communityId, active: true });
if (!community) {
return isGoldenHoneyBadger ? 0 : maxFee;
}
communityFee = communityFee * (community.fee / 100);
🤖 Prompt for AI Agents
In util/index.ts around lines 457 to 460, do not throw when Community.findOne
returns null or inactive; instead treat missing/inactive community as "no
community" and leave the previously computed global fee path intact. Change the
logic to fetch the community (as you already do), then only apply communityFee =
communityFee * (community.fee / 100) if a community was found (and active),
otherwise skip that multiplication so the global fee remains in effect. After
making the change, run: npm run format.

Expand Down
Loading