|
1 | 1 | 'use server' |
2 | 2 |
|
3 | 3 | import { sql } from '@vercel/postgres' |
| 4 | +import Airtable from 'airtable' |
4 | 5 |
|
5 | 6 | async function processPendingInviteJobs() { |
6 | 7 | const { rows } = |
@@ -120,9 +121,110 @@ async function processPendingPersonInitJobs() { |
120 | 121 | ) |
121 | 122 | } |
122 | 123 |
|
| 124 | +async function processLotteryJobs() { |
| 125 | + const { rows } = await sql` |
| 126 | + SELECT * |
| 127 | + FROM background_job |
| 128 | + WHERE type = 'run_lottery' |
| 129 | + AND status = 'pending' |
| 130 | + LIMIT 1; |
| 131 | + ` |
| 132 | + |
| 133 | + if (rows.length === 0) { |
| 134 | + return |
| 135 | + } |
| 136 | + |
| 137 | + const previous = ( |
| 138 | + await sql` |
| 139 | + SELECT * |
| 140 | + FROM background_job |
| 141 | + WHERE type = 'run_lottery' |
| 142 | + AND status = 'completed' |
| 143 | + ORDER BY created_at DESC |
| 144 | + LIMIT 1;` |
| 145 | + ).rows[0] |
| 146 | + |
| 147 | + console.log('Previous lottery job', previous) |
| 148 | + |
| 149 | + if ( |
| 150 | + previous && |
| 151 | + previous.created_at > new Date(Date.now() - 1000 * 60 * 60 * 23) |
| 152 | + ) { |
| 153 | + return |
| 154 | + } |
| 155 | + |
| 156 | + Airtable.configure({ |
| 157 | + apiKey: process.env.AIRTABLE_API_KEY, |
| 158 | + endpointUrl: process.env.AIRTABLE_ENDPOINT_URL, |
| 159 | + }) |
| 160 | + |
| 161 | + const base = Airtable.base('appTeNFYcUiYfGcR6') |
| 162 | + |
| 163 | + const highSeasChannelId = 'C07PZMBUNDS' |
| 164 | + await base('arrpheus_message_requests').create({ |
| 165 | + message_text: `Each day, a newly signed up user will win a free Raspberry Pi Zero! Today's winner is...`, |
| 166 | + target_slack_id: highSeasChannelId, |
| 167 | + requester_identifier: 'cron-job', |
| 168 | + }) |
| 169 | + |
| 170 | + // read all free sticker orders created in the last 24 hours |
| 171 | + const eligibleUsers = await base('people') |
| 172 | + .select({ |
| 173 | + filterByFormula: `AND( |
| 174 | + has_ordered_free_stickers = TRUE(), |
| 175 | + verified_eligible = TRUE(), |
| 176 | + verified_ineligible = FALSE(), |
| 177 | + DATETIME_DIFF(NOW(), verification_updated_at, 'hours') <= 24 |
| 178 | + )`, |
| 179 | + }) |
| 180 | + .all() |
| 181 | + |
| 182 | + const winner = eligibleUsers.sort(() => Math.random() - 0.5)[0] |
| 183 | + console.log('Winner', winner) |
| 184 | + |
| 185 | + // create the order |
| 186 | + const order = await base('shop_orders').create({ |
| 187 | + status: 'fresh', |
| 188 | + shop_item: ['recKV56D2PATOqK4W'], |
| 189 | + recipient: [winner?.id], |
| 190 | + }) |
| 191 | + |
| 192 | + // send a DM to the winner |
| 193 | + const messageRequests = [ |
| 194 | + { |
| 195 | + message_text: `Hey, congrats <@${winner?.fields['slack_id']}>! You won today's free Raspberry Pi Zero! 🎉 We're shipping it to the same address as your sticker bundle.`, |
| 196 | + target_slack_id: winner?.fields['slack_id'], |
| 197 | + requester_identifier: 'cron-job', |
| 198 | + }, |
| 199 | + { |
| 200 | + message_text: `Heads up, <@${winner?.fields['slack_id']}> won today's Raspberry Pi Zero! 🎉`, |
| 201 | + target_slack_id: 'U0C7B14Q3', // notify msw for observability |
| 202 | + requester_identifier: 'cron-job', |
| 203 | + }, |
| 204 | + { |
| 205 | + message_text: `Congratulations to <@${winner?.fields['slack_id']}> for winning a free Raspberry Pi Zero! 🎉 Every day a newly signed up person will get one.`, |
| 206 | + target_slack_id: highSeasChannelId, |
| 207 | + requester_identifier: 'cron-job', |
| 208 | + }, |
| 209 | + ] |
| 210 | + |
| 211 | + const messagePromise = base('arrpheus_message_requests').create( |
| 212 | + messageRequests.map((m) => ({ fields: m })), |
| 213 | + ) |
| 214 | + |
| 215 | + const upsert = await sql` |
| 216 | + UPDATE background_job |
| 217 | + SET status='completed', |
| 218 | + output=${JSON.stringify(order)} |
| 219 | + WHERE type='run_lottery' |
| 220 | + AND status='pending'` |
| 221 | + |
| 222 | + await Promise.all([upsert, messagePromise]) |
| 223 | +} |
123 | 224 | export async function processBackgroundJobs() { |
124 | 225 | await Promise.all([ |
125 | 226 | processPendingInviteJobs(), |
126 | 227 | processPendingPersonInitJobs(), |
| 228 | + processLotteryJobs(), |
127 | 229 | ]) |
128 | 230 | } |
0 commit comments