Skip to content

Commit bc8b114

Browse files
authored
RSVP support (#924)
1 parent f2bd7c5 commit bc8b114

File tree

7 files changed

+142
-8
lines changed

7 files changed

+142
-8
lines changed

src/app.js

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,50 @@ async function processOne(hook) {
589589
fastify.webhooks.info(`raid ${JSON.stringify(hook.message)}`)
590590
const cacheKey = `${hook.message.gym_id}${hook.message.end}${hook.message.pokemon_id}`
591591

592-
if (fastify.cache.get(cacheKey)) {
592+
const raidDetails = fastify.cache.get(cacheKey)
593+
let rsvpDifference = false
594+
const oldRsvpsLen = raidDetails?.rsvps?.length ?? 0
595+
const newRsvpsLen = hook.message.rsvps?.length ?? 0
596+
if (newRsvpsLen > oldRsvpsLen) {
597+
rsvpDifference = true
598+
} else if (raidDetails && raidDetails.rsvps && hook.message.rsvps) {
599+
// Allow for old timeslots to have disappeared, so only compare the
600+
// new ones present
601+
for (let x = 0; x < newRsvpsLen; x++) {
602+
const newRsvp = hook.message.rsvps[x]
603+
604+
let found = false
605+
for (const oldRsvp of raidDetails.rsvps) {
606+
if (newRsvp.timeslot === oldRsvp.timeslot) {
607+
found = true
608+
if (newRsvp.going_count !== oldRsvp.going_count
609+
|| newRsvp.maybe_count !== oldRsvp.maybe_count) {
610+
rsvpDifference = true
611+
}
612+
break
613+
}
614+
}
615+
616+
if (found) {
617+
if (rsvpDifference) break
618+
} else {
619+
// timeslot was not in old rsvps
620+
rsvpDifference = true
621+
break
622+
}
623+
}
624+
}
625+
626+
if (raidDetails && !rsvpDifference) {
593627
fastify.controllerLog.debug(`${hook.message.gym_id}: Raid was sent again too soon, ignoring`)
594628
break
595629
}
596630

597-
fastify.cache.set(cacheKey, 'x')
631+
hook.message.firstNotification = !raidDetails
632+
633+
fastify.cache.set(cacheKey, {
634+
rsvps: hook.message.rsvps,
635+
})
598636
}
599637

600638
await processHook(hook)

src/controllers/raid.js

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class Raid extends Controller {
99
const { areastring, strictareastring } = this.buildAreaString(data.matched)
1010

1111
let query = `
12-
select humans.id, humans.name, humans.type, humans.language, humans.latitude, humans.longitude, raid.template, raid.distance, raid.clean, raid.ping from raid
12+
select humans.id, humans.name, humans.type, humans.language, humans.latitude, humans.longitude, raid.template, raid.distance, raid.clean, raid.ping, raid.rsvp_changes from raid
1313
join humans on (humans.id = raid.id and humans.current_profile_no = raid.profile_no)
1414
where humans.enabled = 1 and humans.admin_disable = false and (humans.blocked_alerts IS NULL OR humans.blocked_alerts NOT LIKE '%raid%') and
1515
(pokemon_id=${data.pokemon_id} or (pokemon_id=9000 and (raid.level=${data.level} or raid.level=90))) and
@@ -72,7 +72,7 @@ class Raid extends Controller {
7272
const { areastring, strictareastring } = this.buildAreaString(data.matched)
7373

7474
let query = `
75-
select humans.id, humans.name, humans.type, humans.language, humans.latitude, humans.longitude, egg.template, egg.distance, egg.clean, egg.ping from egg
75+
select humans.id, humans.name, humans.type, humans.language, humans.latitude, humans.longitude, egg.template, egg.distance, egg.clean, egg.ping, egg.rsvp_changes from egg
7676
join humans on (humans.id = egg.id and humans.current_profile_no = egg.profile_no)
7777
where humans.enabled = 1 and humans.admin_disable = false and (humans.blocked_alerts IS NULL OR humans.blocked_alerts NOT LIKE '%egg%') and
7878
(egg.level = ${data.level} or egg.level = 90) and
@@ -165,7 +165,8 @@ class Raid extends Controller {
165165
data.gymColor = this.GameData.utilData.teams[data.team_id].color
166166
data.ex = !!(data.ex_raid_eligible ?? data.is_ex_raid_eligible)
167167
data.gymUrl = data.gym_url || data.url || ''
168-
const disappearTime = moment(data.end * 1000).tz(geoTz.find(data.latitude, data.longitude)[0].toString())
168+
const timezone = geoTz.find(data.latitude, data.longitude)[0].toString()
169+
const disappearTime = moment(data.end * 1000).tz(timezone)
169170
data.disappearTime = disappearTime.format(this.config.locale.time)
170171
data.applemap = data.appleMapUrl // deprecated
171172
data.mapurl = data.googleMapUrl // deprecated
@@ -188,6 +189,22 @@ class Raid extends Controller {
188189
return []
189190
}
190191

192+
const unixMsNow = new Date().getTime()
193+
194+
if (data.rsvps) {
195+
const newRsvps = []
196+
for (const rsvp of data.rsvps) {
197+
if (rsvp.timeslot > unixMsNow) {
198+
rsvp.timeSlot = Math.ceil(rsvp.timeslot / 1000)
199+
rsvp.time = moment(rsvp.timeslot).tz(timezone).format(this.config.locale.time)
200+
rsvp.goingCount = rsvp.going_count || 0
201+
rsvp.maybeCount = rsvp.maybe_count || 0
202+
newRsvps.push(rsvp)
203+
}
204+
}
205+
data.rsvps = newRsvps
206+
}
207+
191208
if (data.pokemon_id) {
192209
data.form ??= 0
193210
const monster = this.GameData.monsters[`${data.pokemon_id}_${data.form}`] || this.GameData.monsters[`${data.pokemon_id}_0`]
@@ -271,6 +288,18 @@ class Raid extends Controller {
271288
await require('./common/weather').calculateForecastImpact(data, this.GameData, weatherCellId, this.weatherData, data.end, this.config)
272289

273290
for (const cares of whoCares) {
291+
if (cares.rsvp_changes === 0 && !data.firstNotification) {
292+
this.log.debug(`${logReference}: Not creating raid alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template} - no rsvp changes`, cares)
293+
// eslint-disable-next-line no-continue
294+
continue
295+
}
296+
297+
if (cares.rsvp_changes === 2 && (!data.rsvps || data.rsvps?.length === 0)) {
298+
this.log.debug(`${logReference}: Not creating raid alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template} - only rsvp changes`, cares)
299+
// eslint-disable-next-line no-continue
300+
continue
301+
}
302+
274303
this.log.debug(`${logReference}: Creating raid alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template}`, cares)
275304

276305
const rateLimitTtr = this.getRateLimitTimeToRelease(cares.id)
@@ -520,6 +549,17 @@ class Raid extends Controller {
520549
data.staticmap = data.staticMap // deprecated
521550

522551
for (const cares of whoCares) {
552+
if (cares.rsvp_changes === 0 && !data.firstNotification) {
553+
this.log.debug(`${logReference}: Not creating egg alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template} - no rsvp changes`, cares)
554+
// eslint-disable-next-line no-continue
555+
continue
556+
}
557+
558+
if (cares.rsvp_changes === 2 && (!data.rsvps || data.rsvps?.length === 0)) {
559+
this.log.debug(`${logReference}: Not creating egg alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template} - only rsvp changes`, cares)
560+
// eslint-disable-next-line no-continue
561+
continue
562+
}
523563
this.log.debug(`${logReference}: Creating egg alert for ${cares.id} ${cares.name} ${cares.type} ${cares.language} ${cares.template}`, cares)
524564
const rateLimitTtr = this.getRateLimitTimeToRelease(cares.id)
525565
if (rateLimitTtr) {

src/lib/db/migrations/v19_rsvps.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const { log } = require('../../logger')
2+
3+
exports.up = async function migrationUp(knex) {
4+
await knex.schema.alterTable('raid', (table) => {
5+
table.tinyint('rsvp_changes', 8).notNullable().defaultTo(0)
6+
})
7+
log.info('Rsvp raid migration applied')
8+
}
9+
10+
exports.down = async function migrationDown(knex) {
11+
log.info(knex)
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const { log } = require('../../logger')
2+
3+
exports.up = async function migrationUp(knex) {
4+
await knex.schema.alterTable('egg', (table) => {
5+
table.tinyint('rsvp_changes', 8).notNullable().defaultTo(0)
6+
})
7+
log.info('Rsvp egg migration applied')
8+
}
9+
10+
exports.down = async function migrationDown(knex) {
11+
log.info(knex)
12+
}

src/lib/poracleMessage/commands/egg.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ exports.run = async (client, msg, args, options) => {
4545
let team = 4
4646
let template = client.config.general.defaultTemplateName
4747
let clean = false
48+
let rsvpChanges = 0
4849
const levelSet = new Set()
4950
const pings = msg.getPings()
5051

@@ -59,6 +60,9 @@ exports.run = async (client, msg, args, options) => {
5960
else if (element === 'harmony' || element === 'gray') team = 0
6061
else if (element === 'everything') Object.keys(client.GameData.utilData.raidLevels).forEach((x) => levelSet.add(+x))
6162
else if (element === 'clean') clean = true
63+
else if (element === 'no rsvp') rsvpChanges = 0
64+
else if (element === 'rsvp') rsvpChanges = 1
65+
else if (element === 'rsvp only') rsvpChanges = 2
6266
})
6367
if (client.config.tracking.defaultDistance !== 0 && distance === 0 && !msg.isFromAdmin) distance = client.config.tracking.defaultDistance
6468
if (client.config.tracking.maxDistance !== 0 && distance > client.config.tracking.maxDistance && !msg.isFromAdmin) distance = client.config.tracking.maxDistance
@@ -93,6 +97,7 @@ exports.run = async (client, msg, args, options) => {
9397
clean: +clean,
9498
level: +lvl,
9599
gym_id: null,
100+
rsvp_changes: +rsvpChanges,
96101
}))
97102

98103
const tracked = await client.query.selectAllQuery('egg', { id: target.id, profile_no: currentProfileNo })

src/lib/poracleMessage/commands/raid.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ exports.run = async (client, msg, args, options) => {
5151
let clean = false
5252
const evolution = 9000
5353
let move = 9000
54+
let rsvpChanges = 0
5455
const levelSet = new Set()
5556
const pings = msg.getPings()
5657
const formNames = args.filter((arg) => arg.match(client.re.formRe)).map((arg) => client.translatorFactory.reverseTranslateCommand(arg.match(client.re.formRe)[2], true).toLowerCase())
@@ -104,6 +105,9 @@ exports.run = async (client, msg, args, options) => {
104105
else if (element === 'harmony' || element === 'gray') team = 0
105106
else if (element === 'everything') Object.keys(client.GameData.utilData.raidLevels).forEach((x) => levelSet.add(+x))
106107
else if (element === 'clean') clean = true
108+
else if (element === 'no rsvp') rsvpChanges = 0
109+
else if (element === 'rsvp') rsvpChanges = 1
110+
else if (element === 'rsvp only') rsvpChanges = 2
107111
}
108112
if (client.config.tracking.defaultDistance !== 0 && distance === 0 && !msg.isFromAdmin) distance = client.config.tracking.defaultDistance
109113
if (client.config.tracking.maxDistance !== 0 && distance > client.config.tracking.maxDistance && !msg.isFromAdmin) distance = client.config.tracking.maxDistance
@@ -141,6 +145,7 @@ exports.run = async (client, msg, args, options) => {
141145
evolution: +evolution,
142146
move: +move,
143147
gym_id: null,
148+
rsvp_changes: +rsvpChanges,
144149
}))
145150

146151
levels.forEach((level) => {
@@ -159,6 +164,7 @@ exports.run = async (client, msg, args, options) => {
159164
evolution: +evolution,
160165
move: +move,
161166
gym_id: null,
167+
rsvp_changes: +rsvpChanges,
162168
})
163169
})
164170

src/lib/poracleMessage/commands/tracked.js

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,23 @@ async function raidRowText(config, translator, GameData, raid, scannerQuery) {
6666
let gymNameText = null
6767
if (raid.gym_id) gymNameText = scannerQuery ? await scannerQuery.getGymName(raid.gym_id) || raid.gym_id : raid.gym_id
6868

69+
let rsvpText = ''
70+
switch (raid.rsvp_changes) {
71+
case 0: rsvpText = translator.translate('without rsvp updates')
72+
break
73+
case 1: rsvpText = translator.translate('including rsvp updates')
74+
break
75+
case 2: rsvpText = translator.translate('rsvp only')
76+
break
77+
default: break
78+
}
6979
const moveName = raid.move !== 9000 && GameData.moves[raid.move] ? `${translator.translate(GameData.moves[raid.move].name)}/${translator.translate(GameData.moves[raid.move].type)}` : ''
7080

7181
if (+raid.pokemon_id === 9000) {
72-
return `**${raid.level === 90 ? translator.translate('All level') : `${translator.translate('level').charAt(0).toUpperCase() + translator.translate('level').slice(1)} ${raid.level}`} ${translator.translate('raids')}** ${raid.distance ? ` | ${translator.translate('distance')}: ${raid.distance}m` : ''}${moveName ? ` | ${translator.translate('with move')} ${moveName}` : ''}${raid.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${raid.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, raid)}${raid.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''}`
82+
return `**${raid.level === 90 ? translator.translate('All level') : `${translator.translate('level').charAt(0).toUpperCase() + translator.translate('level').slice(1)} ${raid.level}`} ${translator.translate('raids')}** ${raid.distance ? ` | ${translator.translate('distance')}: ${raid.distance}m` : ''}${moveName ? ` | ${translator.translate('with move')} ${moveName}` : ''}${raid.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${raid.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, raid)}${raid.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''} ${rsvpText}`
7383
}
7484

75-
return `**${monsterName}**${formName ? ` ${translator.translate('form')}: ${formName}` : ''}${raid.distance ? ` | ${translator.translate('distance')}: ${raid.distance}m` : ''}${moveName ? ` | ${translator.translate('with move')} ${moveName}` : ''}${raid.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${raid.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, raid)}${raid.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''}`
85+
return `**${monsterName}**${formName ? ` ${translator.translate('form')}: ${formName}` : ''}${raid.distance ? ` | ${translator.translate('distance')}: ${raid.distance}m` : ''}${moveName ? ` | ${translator.translate('with move')} ${moveName}` : ''}${raid.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${raid.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, raid)}${raid.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''} ${rsvpText}`
7686
}
7787

7888
async function gymRowText(config, translator, GameData, gym, scannerQuery) {
@@ -107,7 +117,18 @@ async function eggRowText(config, translator, GameData, egg, scannerQuery) {
107117
let gymNameText = null
108118
if (egg.gym_id) gymNameText = scannerQuery ? await scannerQuery.getGymName(egg.gym_id) || egg.gym_id : egg.gym_id
109119

110-
return `**${egg.level === 90 ? translator.translate('All level') : `${translator.translate('level').charAt(0).toUpperCase() + translator.translate('level').slice(1)} ${egg.level}`} ${translator.translate('eggs')}** ${egg.distance ? ` | ${translator.translate('distance')}: ${egg.distance}m` : ''} ${egg.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${egg.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, egg)}${egg.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''}`
120+
let rsvpText = ''
121+
switch (egg.rsvp_changes) {
122+
case 0: rsvpText = translator.translate('without rsvp updates')
123+
break
124+
case 1: rsvpText = translator.translate('including rsvp updates')
125+
break
126+
case 2: rsvpText = translator.translate('rsvp only')
127+
break
128+
default: break
129+
}
130+
131+
return `**${egg.level === 90 ? translator.translate('All level') : `${translator.translate('level').charAt(0).toUpperCase() + translator.translate('level').slice(1)} ${egg.level}`} ${translator.translate('eggs')}** ${egg.distance ? ` | ${translator.translate('distance')}: ${egg.distance}m` : ''} ${egg.team === 4 ? '' : ` | ${translator.translate('controlled by')} ${raidTeam}`}${egg.exclusive ? ` | ${translator.translate('must be an EX Gym')}` : ''} ${standardText(config, translator, egg)}${egg.gym_id ? ` ${translator.translate('at gym ')} ${gymNameText}` : ''} ${rsvpText}`
111132
}
112133

113134
function questRowText(config, translator, GameData, quest) {

0 commit comments

Comments
 (0)