Telegram: echo payouts into a shared cross-program topic
telegramOnEvent now builds the line once per target: the existing proof feed (telegramChatId) and a new echo target (telegramEchoChatId + telegramEchoTopicId, telegramEchoEvents). AwardPaid events are now posted too. Echo lines carry an InstantAdPay prefix since RM Circle shares the topic. Admin labels added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -485,7 +485,7 @@
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// site settings: key / value rows; booleans as checkboxes, numbers stay numbers
|
// site settings: key / value rows; booleans as checkboxes, numbers stay numbers
|
||||||
const SITE_META = { siteName: 'Site name', tagline: 'Tagline', rehearsal: 'Testnet rehearsal banner', defaultSponsorId: 'Fallback sponsor (member #)', walletConnectProjectId: 'WalletConnect project id', moonpayPublicKey: 'MoonPay public key', telegramBotToken: 'Telegram proof feed: bot token', telegramChatId: 'Telegram proof feed: chat id', telegramTopicId: 'Telegram proof feed: topic id (optional)', telegramEvents: 'Telegram proof feed: events (payouts | payouts+purchases | all)', telegramCtaUrl: 'Telegram proof feed: join link under each post', pnlFixedMonthlyUsd: 'P&L: fixed monthly cost (USD)' };
|
const SITE_META = { siteName: 'Site name', tagline: 'Tagline', rehearsal: 'Testnet rehearsal banner', defaultSponsorId: 'Fallback sponsor (member #)', walletConnectProjectId: 'WalletConnect project id', moonpayPublicKey: 'MoonPay public key', telegramBotToken: 'Telegram proof feed: bot token', telegramChatId: 'Telegram proof feed: chat id', telegramTopicId: 'Telegram proof feed: topic id (optional)', telegramEvents: 'Telegram proof feed: events (payouts | payouts+purchases | all)', telegramCtaUrl: 'Telegram proof feed: join link under each post', telegramEchoChatId: 'Telegram echo (shared payments topic): chat id', telegramEchoTopicId: 'Telegram echo: topic id', telegramEchoEvents: 'Telegram echo: events (payouts | payouts+purchases | all)', pnlFixedMonthlyUsd: 'P&L: fixed monthly cost (USD)' };
|
||||||
function drawSite() {
|
function drawSite() {
|
||||||
const wrap = $('siteForm');
|
const wrap = $('siteForm');
|
||||||
wrap.innerHTML = Object.entries(siteObj).map(([k, v]) => '<div class="kv-row"><span class="k" title="' + esc(k) + '">' + esc(SITE_META[k] || humanize(k)) + '</span>'
|
wrap.innerHTML = Object.entries(siteObj).map(([k, v]) => '<div class="kv-row"><span class="k" title="' + esc(k) + '">' + esc(SITE_META[k] || humanize(k)) + '</span>'
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ function siteConfig() {
|
|||||||
rehearsal: true, // shows the testnet banner; flipped off at mainnet launch
|
rehearsal: true, // shows the testnet banner; flipped off at mainnet launch
|
||||||
// payment-proof Telegram feed (blank = off) and the P&L pane's fixed monthly cost
|
// payment-proof Telegram feed (blank = off) and the P&L pane's fixed monthly cost
|
||||||
telegramBotToken: '', telegramChatId: '', telegramTopicId: '', telegramEvents: 'payouts', telegramCtaUrl: 'https://instantadpay.com/',
|
telegramBotToken: '', telegramChatId: '', telegramTopicId: '', telegramEvents: 'payouts', telegramCtaUrl: 'https://instantadpay.com/',
|
||||||
|
telegramEchoChatId: '', telegramEchoTopicId: '', telegramEchoEvents: 'payouts', // shared cross-program payments topic
|
||||||
telegramAdminChatId: '', // private chat for admin alerts (sign-up guard bursts); falls back to ADMIN_EMAIL
|
telegramAdminChatId: '', // private chat for admin alerts (sign-up guard bursts); falls back to ADMIN_EMAIL
|
||||||
launchAt: '', // public launch moment, ISO 8601 with offset (e.g. 2026-09-18T19:00:00-05:00): countdown on /launch + dashboard mark
|
launchAt: '', // public launch moment, ISO 8601 with offset (e.g. 2026-09-18T19:00:00-05:00): countdown on /launch + dashboard mark
|
||||||
geoTier1: '', // comma-separated ISO country codes; empty = built-in default (US, CA, GB, AU, NZ, IE, DE, FR, NL, SE, NO, DK, FI, CH, AT, BE)
|
geoTier1: '', // comma-separated ISO country codes; empty = built-in default (US, CA, GB, AU, NZ, IE, DE, FR, NL, SE, NO, DK, FI, CH, AT, BE)
|
||||||
@@ -526,22 +527,29 @@ async function emailOnEvent(ev) {
|
|||||||
// payment-proof Telegram feed (same pattern as the RM Circle proof channel): one compact
|
// payment-proof Telegram feed (same pattern as the RM Circle proof channel): one compact
|
||||||
// line per event, admin-configured under Settings > Site (telegramBotToken, telegramChatId,
|
// line per event, admin-configured under Settings > Site (telegramBotToken, telegramChatId,
|
||||||
// optional telegramTopicId, telegramEvents = payouts | payouts+purchases | all, telegramCtaUrl)
|
// optional telegramTopicId, telegramEvents = payouts | payouts+purchases | all, telegramCtaUrl)
|
||||||
|
// A second target, telegramEchoChatId + telegramEchoTopicId (+ telegramEchoEvents), echoes
|
||||||
|
// the same lines into a shared cross-program payments topic that RM Circle also posts to,
|
||||||
|
// so every line there carries the program name.
|
||||||
async function telegramOnEvent(ev) {
|
async function telegramOnEvent(ev) {
|
||||||
const sc = siteConfig();
|
const sc = siteConfig();
|
||||||
if (!sc.telegramBotToken || !sc.telegramChatId || !ev) return;
|
if (!sc.telegramBotToken || !ev) return;
|
||||||
const mode = String(sc.telegramEvents || 'payouts');
|
if (!sc.telegramChatId && !sc.telegramEchoChatId) return;
|
||||||
const names = await accounts.namesForMembers([ev.recipientId, ev.buyerId, ev.sponsorId, ev.newBuyerId, ev.id].filter(Boolean)).catch(() => ({}));
|
const names = await accounts.namesForMembers([ev.recipientId, ev.buyerId, ev.sponsorId, ev.newBuyerId, ev.id].filter(Boolean)).catch(() => ({}));
|
||||||
const who = id => '#' + id + (names[id] ? ' @' + names[id] : '');
|
const who = id => '#' + id + (names[id] ? ' @' + names[id] : '');
|
||||||
const cc = chain.getConfig();
|
const cc = chain.getConfig();
|
||||||
const tx = (cc.explorer ? cc.explorer.replace(/\/+$/, '') : 'https://polygonscan.com') + '/tx/' + ev.tx;
|
const tx = (cc.explorer ? cc.explorer.replace(/\/+$/, '') : 'https://polygonscan.com') + '/tx/' + ev.tx;
|
||||||
|
const build = (mode) => {
|
||||||
let line = null;
|
let line = null;
|
||||||
if (ev.type === 'TierPaid') line = '\u{1F4B8} Level ' + ev.tier + ' payout: <b>' + weiToPol(ev.amountWei) + ' POL</b> \u2192 ' + who(ev.recipientId);
|
if (ev.type === 'TierPaid') line = '\u{1F4B8} Level ' + ev.tier + ' payout: <b>' + weiToPol(ev.amountWei) + ' POL</b> \u2192 ' + who(ev.recipientId);
|
||||||
else if (ev.type === 'BuyerCounted' && mode !== 'payouts') line = '\u2B50 ' + who(ev.sponsorId) + ' now has <b>' + ev.newCount + '</b> qualifying buyer' + (ev.newCount === 1 ? '' : 's') + (ev.newCount === 2 ? ' \u00b7 level 2 open' : ev.newCount === 5 ? ' \u00b7 level 3 open' : '');
|
else if (ev.type === 'BuyerCounted' && mode !== 'payouts') line = '\u2B50 ' + who(ev.sponsorId) + ' now has <b>' + ev.newCount + '</b> qualifying buyer' + (ev.newCount === 1 ? '' : 's') + (ev.newCount === 2 ? ' \u00b7 level 2 open' : ev.newCount === 5 ? ' \u00b7 level 3 open' : '');
|
||||||
else if (ev.type === 'Purchase' && mode !== 'payouts') line = '\u{1F9FE} ' + who(ev.buyerId) + ' bought a $' + Math.round(ev.priceCents / 100) + ' package';
|
else if (ev.type === 'Purchase' && mode !== 'payouts') line = '\u{1F9FE} ' + who(ev.buyerId) + ' bought a $' + Math.round(ev.priceCents / 100) + ' package';
|
||||||
|
else if (ev.type === 'AwardPaid') line = '\u{1F4B8} Award payout: <b>' + weiToPol(ev.amountWei) + ' POL</b> \u2192 ' + who(ev.toId);
|
||||||
else if (ev.type === 'MemberActivated' && mode === 'all') line = '\u{1F91D} ' + who(ev.id) + ' switched on payouts';
|
else if (ev.type === 'MemberActivated' && mode === 'all') line = '\u{1F91D} ' + who(ev.id) + ' switched on payouts';
|
||||||
if (!line) return;
|
if (!line) return null;
|
||||||
const text = line + ' \u00b7 <a href="' + tx + '">verify</a>' + (sc.telegramCtaUrl ? '\n<a href="' + sc.telegramCtaUrl + '">Join free</a>' : '');
|
return line + ' \u00b7 <a href="' + tx + '">verify</a>' + (sc.telegramCtaUrl ? '\n<a href="' + sc.telegramCtaUrl + '">Join free</a>' : '');
|
||||||
await telegramSend(sc.telegramChatId, text, sc.telegramTopicId);
|
};
|
||||||
|
if (sc.telegramChatId) { const t = build(String(sc.telegramEvents || 'payouts')); if (t) await telegramSend(sc.telegramChatId, t, sc.telegramTopicId); }
|
||||||
|
if (sc.telegramEchoChatId) { const t = build(String(sc.telegramEchoEvents || 'payouts')); if (t) await telegramSend(sc.telegramEchoChatId, '\u{1F7E0} <b>InstantAdPay</b> \u00b7 ' + t, sc.telegramEchoTopicId); }
|
||||||
}
|
}
|
||||||
// one sendMessage call; never throws, never logs the token
|
// one sendMessage call; never throws, never logs the token
|
||||||
async function telegramSend(chatId, text, threadId) {
|
async function telegramSend(chatId, text, threadId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user