Add auto-tweet of on-chain payout proof to @cryptoteambuild (Blotato)
New tweet.js posts a tweet to X via Blotato each time the indexer emits a NEW team payout. Org-gated to the #21 organization; fires on all payout types. Ships DISABLED (config.tweetEnabled default off / env TWEET_ON_PAYOUT), so nothing posts until explicitly turned on. Safety: dedupes by tx key (persisted to DATA_DIR/tweeted-payouts.json) so restarts never re-post; a min-gap queue keeps bursts under Blotato's 30/min limit; API key read from env BLOTATO_API_KEY or DATA_DIR key file, never committed or logged. Varied emoji/hashtag templates with a CTA (+UTM) to the main page; deterministic template pick avoids X duplicate-content rejection. Admin config allowlist gains tweetEnabled, tweetCtaUrl, tweetHashtags, blotatoTwitterId. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { URL } = require('url');
|
||||
const chain = require('./chain');
|
||||
const tweet = require('./tweet');
|
||||
|
||||
const PORT = Number(process.env.PORT || 3000);
|
||||
const ROOT = __dirname;
|
||||
@@ -489,7 +490,7 @@ async function handleApi(req,res,pathname){
|
||||
const maxOrder=sponsors.reduce((m,s)=>Math.max(m,s.sortOrder||0),0);sponsors.push({id:String(id).trim(),name:String(name).trim(),parentId:String(parentId||'').trim(),directs:0,level,status:sponsors.some(s=>s.status==='active')?'waiting':'active',sortOrder:maxOrder+10,clicks:0,notes:String(notes||'').trim(),email:String(email||'').trim().slice(0,120)});sponsors=normalizeStatuses(sponsors);saveSponsors(sponsors);return json(res,201,{sponsors});
|
||||
}
|
||||
if(req.method==='PATCH'&&pathname==='/api/admin/config'){
|
||||
const b=await bodyJson(req),cur=getConfig(),next={...cur};for(const k of ['siteName','programName','bridgeHeadline','bridgeSubheadline','premiumEntryPol','dappReferralBaseUrl','telegramUrl','supportLabel','showSponsorName','showQueueProgress','bemobPostbackUrl','telegramBotToken','telegramChatId','telegramTopicId','teamRootId','emailFrom','teamAlertEmail','ownerIds','ownerAlertEmail','orgRootId'])if(Object.prototype.hasOwnProperty.call(b,k))next[k]=b[k];next.premiumEntryPol=Number(next.premiumEntryPol)||362;next.updatedAt=new Date().toISOString();writeJson(CONFIG_FILE,next);return json(res,200,{config:next});
|
||||
const b=await bodyJson(req),cur=getConfig(),next={...cur};for(const k of ['siteName','programName','bridgeHeadline','bridgeSubheadline','premiumEntryPol','dappReferralBaseUrl','telegramUrl','supportLabel','showSponsorName','showQueueProgress','bemobPostbackUrl','telegramBotToken','telegramChatId','telegramTopicId','teamRootId','emailFrom','teamAlertEmail','ownerIds','ownerAlertEmail','orgRootId','tweetEnabled','tweetCtaUrl','tweetHashtags','blotatoTwitterId'])if(Object.prototype.hasOwnProperty.call(b,k))next[k]=b[k];next.premiumEntryPol=Number(next.premiumEntryPol)||362;next.updatedAt=new Date().toISOString();writeJson(CONFIG_FILE,next);return json(res,200,{config:next});
|
||||
}
|
||||
const m=pathname.match(/^\/api\/admin\/sponsors\/([^/]+)(?:\/(increment|activate|qualify|reset|move))?$/);
|
||||
if(m){const id=decodeURIComponent(m[1]),action=m[2]||null;let sponsors=getSponsors(),idx=sponsors.findIndex(s=>s.id===id);if(idx<0)return json(res,404,{error:'Sponsor not found.'});
|
||||
@@ -640,6 +641,14 @@ chain.startIndexer(evt=>{
|
||||
if(rec&&rec.email&&!sent.has(rec.email.toLowerCase()))sendPaidEmail(rec.email,'there',evt,unsubUrl(evt.toId));
|
||||
}
|
||||
}catch(e){console.error('paid email error',e.message)}
|
||||
// Auto-tweet on-chain payout proof to @cryptoteambuild via Blotato (Marty
|
||||
// 2026-08-15). Org-gated to the #21 organization; OFF unless config.tweetEnabled.
|
||||
try{
|
||||
if(evt.type==='payout'){
|
||||
const orgRoot=Number(getConfig().orgRootId)||21;
|
||||
if(chain.isInTeam(evt.toId,orgRoot))tweet.queuePayoutTweet(evt,getConfig());
|
||||
}
|
||||
}catch(e){console.error('tweet hook error',e.message)}
|
||||
// Auto-count directs + AUTO-ADVANCE (Marty 2026-08-15): a new registration
|
||||
// whose referrer sits in the rotation queue increments that sponsor's directs.
|
||||
// When it reaches 2/2 the sponsor is auto-qualified and the next waiting
|
||||
|
||||
Reference in New Issue
Block a user