-
Notifications
You must be signed in to change notification settings - Fork 134
Add counterparty requirements customization #794
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
1ed026a
ff4a54a
36b0126
9ee2c7e
316f8cc
335e486
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import Settings from './settings'; | ||
| import Requirements from './requirements'; | ||
|
|
||
| export default { Settings }; | ||
| export default { Settings, Requirements }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| import { Scenes } from 'telegraf'; | ||
| import { | ||
| CommunityContext, | ||
| CommunityWizardState, | ||
| } from '../../community/communityContext'; | ||
| import { Message } from 'telegraf/typings/core/types/typegram'; | ||
| import { logger } from '../../../../logger'; | ||
|
|
||
| function make() { | ||
| const resetMessage = async (ctx: CommunityContext, next: () => void) => { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| delete state.feedback; | ||
| delete state.error; | ||
| next(); | ||
| }; | ||
| async function mainData(ctx: CommunityContext) { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| const { user } = state; | ||
| return { | ||
| min_days_using_bot: | ||
| user.counterparty_requirements?.min_days_using_bot || 0, | ||
| min_completed_orders: | ||
| user.counterparty_requirements?.min_completed_orders || 0, | ||
| }; | ||
| } | ||
| async function updateMessage(ctx: CommunityContext) { | ||
| try { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| ctx.i18n.locale(state.language); | ||
| const { message, error } = state; | ||
|
|
||
| if (message === undefined) throw new Error('message is undefined'); | ||
|
|
||
| const errorText = (error => { | ||
| if (!error) return; | ||
| return '<strong>⚠️ ERROR</strong>\n' + ctx.i18n.t(error.i18n, error); | ||
| })(error); | ||
| const feedbackText = (feedback => { | ||
| if (!feedback) return; | ||
| if (typeof feedback === 'string') return feedback; | ||
| return ctx.i18n.t(feedback.i18n, feedback); | ||
| })(state.feedback); | ||
| const extras = [errorText, feedbackText].filter(e => e); | ||
|
|
||
| const main = ctx.i18n.t('user_requirements', await mainData(ctx)); | ||
| const str = [main, ...extras].filter(e => e).join('\n'); | ||
|
|
||
| const messageChanged = str !== message.text; | ||
| if (!messageChanged) return; | ||
|
|
||
| const msg = await ctx.telegram.editMessageText( | ||
| message.chat.id, | ||
| message.message_id, | ||
| undefined, | ||
| str, | ||
| { | ||
| parse_mode: 'HTML', | ||
| link_preview_options: { is_disabled: true }, | ||
| } as any, | ||
| ); | ||
| state.message = msg as Message.TextMessage; | ||
| state.message.text = str; | ||
| } catch (err) { | ||
| logger.error(err); | ||
| } | ||
| } | ||
| async function initHandler(ctx: CommunityContext) { | ||
| try { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| const { user } = state; | ||
| state.language = user.lang || ctx.from?.language_code; | ||
| const str = ctx.i18n.t('user_requirements', await mainData(ctx)); | ||
| const msg = await ctx.reply(str, { parse_mode: 'HTML' }); | ||
| state.message = msg; | ||
| state.message.text = str; | ||
| } catch (err) { | ||
| logger.error(err); | ||
| } | ||
| } | ||
| const scene = new Scenes.WizardScene( | ||
| 'USER_COUNTERPARTY_REQUIREMENTS', | ||
| async (ctx: CommunityContext) => { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| ctx.user = state.user; | ||
| if (!state.message) return initHandler(ctx); | ||
| await ctx.deleteMessage(); | ||
| state.error = { | ||
| i18n: 'generic_error', | ||
| }; | ||
| await updateMessage(ctx); | ||
| }, | ||
| ); | ||
|
|
||
| scene.command( | ||
| 'counterpartyage', | ||
| resetMessage, | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| async (ctx: CommunityContext) => { | ||
| try { | ||
| await ctx.deleteMessage(); | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| if (ctx.message === undefined || !('text' in ctx.message)) | ||
| throw new Error('ctx.message is undefined'); | ||
| const [, days] = ctx.message.text.trim().split(' '); | ||
| const min_days = parseInt(days); | ||
| if (isNaN(min_days) || min_days < 0) throw new Error('NotValidNumber'); | ||
| const user = state.user; | ||
| const maxAge = parseInt( | ||
| process.env.MAX_COUNTERPARTY_AGE_REQUIREMENT || '30', | ||
| ); | ||
| if (min_days > maxAge) { | ||
| state.error = { | ||
| i18n: 'invalid_range', | ||
| command: '/counterpartyage', | ||
| max: maxAge, | ||
| }; | ||
| return await updateMessage(ctx); | ||
| } | ||
| if (!user.counterparty_requirements) { | ||
| user.counterparty_requirements = { | ||
| min_days_using_bot: 0, | ||
| min_completed_orders: 0, | ||
| }; | ||
| } | ||
| user.counterparty_requirements.min_days_using_bot = min_days; | ||
| await user.save(); | ||
| state.feedback = { | ||
| i18n: 'counterpartyage_updated', | ||
| days: min_days, | ||
| }; | ||
| await updateMessage(ctx); | ||
| } catch (err) { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| state.error = { | ||
| i18n: 'invalid_number', | ||
| }; | ||
| await updateMessage(ctx); | ||
| } | ||
|
Comment on lines
+131
to
+137
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid classifying all exceptions as Right now, non-validation failures (e.g., DB save or Telegram API issues) are surfaced to users as input errors, which is misleading and makes incidents harder to diagnose. Proposed fix } catch (err) {
const state = ctx.scene.state as CommunityWizardState;
- state.error = {
- i18n: 'invalid_number',
- };
+ if (err instanceof Error && err.message === 'NotValidNumber') {
+ state.error = { i18n: 'invalid_number' };
+ } else {
+ logger.error(err);
+ state.error = { i18n: 'generic_error' };
+ }
await updateMessage(ctx);
}
@@
} catch (err) {
const state = ctx.scene.state as CommunityWizardState;
- state.error = {
- i18n: 'invalid_number',
- };
+ if (err instanceof Error && err.message === 'NotValidNumber') {
+ state.error = { i18n: 'invalid_number' };
+ } else {
+ logger.error(err);
+ state.error = { i18n: 'generic_error' };
+ }
await updateMessage(ctx);
}Also applies to: 179-185 🤖 Prompt for AI Agents |
||
| }, | ||
| ); | ||
|
|
||
| scene.command( | ||
| 'counterpartyorders', | ||
| resetMessage, | ||
| async (ctx: CommunityContext) => { | ||
| try { | ||
| await ctx.deleteMessage(); | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| if (ctx.message === undefined || !('text' in ctx.message)) | ||
| throw new Error('ctx.message is undefined'); | ||
| const [, orders] = ctx.message.text.trim().split(' '); | ||
| const min_orders = parseInt(orders); | ||
| if (isNaN(min_orders) || min_orders < 0) | ||
| throw new Error('NotValidNumber'); | ||
| const user = state.user; | ||
| const maxOrders = parseInt( | ||
| process.env.MAX_COUNTERPARTY_ORDERS_REQUIREMENT || '10', | ||
| ); | ||
| if (min_orders > maxOrders) { | ||
| state.error = { | ||
| i18n: 'invalid_range', | ||
| command: '/counterpartyorders', | ||
| max: maxOrders, | ||
| }; | ||
| return await updateMessage(ctx); | ||
| } | ||
| if (!user.counterparty_requirements) { | ||
| user.counterparty_requirements = { | ||
| min_days_using_bot: 0, | ||
| min_completed_orders: 0, | ||
| }; | ||
| } | ||
| user.counterparty_requirements.min_completed_orders = min_orders; | ||
| await user.save(); | ||
| state.feedback = { | ||
| i18n: 'counterpartyorders_updated', | ||
| orders: min_orders, | ||
| }; | ||
| await updateMessage(ctx); | ||
| } catch (err) { | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| state.error = { | ||
| i18n: 'invalid_number', | ||
| }; | ||
| await updateMessage(ctx); | ||
| } | ||
| }, | ||
| ); | ||
|
|
||
| scene.command('reset', resetMessage, async (ctx: CommunityContext) => { | ||
| try { | ||
| await ctx.deleteMessage(); | ||
| const state = ctx.scene.state as CommunityWizardState; | ||
| const user = state.user; | ||
| user.counterparty_requirements = { | ||
| min_days_using_bot: 0, | ||
| min_completed_orders: 0, | ||
| }; | ||
| await user.save(); | ||
| state.feedback = { | ||
| i18n: 'requirements_reset', | ||
| }; | ||
| await updateMessage(ctx); | ||
| } catch (err) { | ||
| (ctx.scene.state as CommunityWizardState).error = { | ||
| i18n: 'generic_error', | ||
| }; | ||
| await updateMessage(ctx); | ||
| } | ||
| }); | ||
|
|
||
| return scene; | ||
| } | ||
|
|
||
| export default make(); | ||
Uh oh!
There was an error while loading. Please reload this page.