Gamification e inviti

Quando si utilizza il plugin Gamification, i punti vengono assegnati per gli inviti riscattati.
Questo è facilmente abusabile inviando inviti e riscattandoli con un account duplicato (falso).
Quando un tale account falso viene rimosso dall’amministratore, il comportamento del plugin gamification (e del sistema di inviti) dipende da come è stato inviato l’invito.

  • Se l’invito era legato a uno specifico indirizzo email e l’utente viene rimosso, allora sia il record invite che i record user_invite vengono eliminati definitivamente (!). La prossima volta che il job Sidekiq UpdateScoresFor* viene eseguito, il plugin gamification dedurrà di nuovo i punti assegnati dal punteggio.

  • Se l’invito non era legato a uno specifico indirizzo email e l’utente viene rimosso, allora il record invited_users verrà rimosso, ma il record invite rimarrà. Il valore redemption_count non sarà decrementato. Questo ha senso da un punto di vista perché il riscatto dell’invito è avvenuto, anche se l’utente è stato rimosso successivamente. Ma il plugin Gamification utilizza redemption_count per calcolare il punteggio quindi i punti non verranno dedotti.

Durante il debug di questo, ho anche scoperto che il job del punteggio considererà solo gli inviti che hanno meno di 10 giorni. Quindi, se un invito viene riscattato dopo 11 giorni, non verranno assegnati punti. Stavo per dire 'Suppongo che debba guardare updated_at invece di created_at ma quando il conteggio dei riscatti per l’invito viene aumentato, il timestamp updated_at non viene toccato.

11 Mi Piace

Qualcosa del genere funzionerebbe meglio (adeguato al formato della query valutabile - questo è un test per l’esploratore di dati :slight_smile:):

-- [params]
-- date :start_date
-- date :end_date

SELECT 
    invited_by_id AS user_id,
    COUNT(*) AS user_invites,
    COUNT(*) * 10 AS invite_score
FROM invited_users iu
  JOIN invites i ON i.id = iu.invite_id
  JOIN users u ON u.id = iu.user_id
WHERE iu.redeemed_at::date BETWEEN :start_date AND :end_date
  AND iu.user_id <> i.invited_by_id 
  AND u.created_at > iu.redeemed_at
GROUP BY invited_by_id
ORDER BY user_invites DESC

Quando un utente viene eliminato, viene rimosso dalla tabella invited_users, quindi non sarebbe più nel conteggio. Se l’eliminazione avvenisse entro 10 giorni, verrebbe corretta automaticamente, se più lunga sarebbe necessario un aggiornamento manuale del punteggio.

L’utilizzo della data redeemed_at terrebbe conto degli inviti creati più di 10 giorni fa.

AND iu.user_id <> i.invited_by_id escluderebbe anche gli auto-inviti.

L’unione della tabella users e l’aggiunta di AND u.created_at > iu.redeemed_at escluderebbero anche l’invito di utenti esistenti.

3 Mi Piace

Questo sarebbe un buon approccio, tranne per una cosa:

Questo non funziona bene. A volte l’utente viene creato leggermente prima che avvenga il riscatto. Non ho idea del perché. Per lo più decimi di secondo, ma ho trovato anche alcuni decine di secondi.

Testato su un database reale.

select
  iu.redeemed_at iu_AS redeemed_at,
  u.created_at AS u_created_at,
  u.created_at > iu.redeemed_at AS u_created_gt_iu_redeemed
from invited_users iu
left join users u on u.id = iu.user_id
where iu.redeemed_at is not null
order by iu.id desc;
       iu_redeemed_at       |        u_created_at        | u_created_gt_iu_redeemed
----------------------------+----------------------------+--------------------------
 2023-09-08 00:00:47.557057 | 2023-09-08 00:00:48.376446 | t
 2023-08-25 20:09:03.486362 | 2023-08-25 20:09:03.201357 | f
 2023-08-15 23:38:32.271709 | 2023-08-15 23:38:33.570299 | t
 2023-08-14 10:44:34.19912  | 2023-08-14 10:44:35.429371 | t
 2023-08-12 13:41:10.428013 | 2023-08-12 13:41:11.733973 | t
 2023-07-31 17:58:13.511289 | 2023-07-31 17:57:50.427111 | f
 2023-07-23 00:56:33.455185 | 2023-07-23 00:55:47.999263 | f
 2023-07-19 08:42:44.908096 | 2023-07-19 08:42:46.040201 | t
 2023-06-30 09:11:38.829692 | 2023-06-30 09:11:39.618586 | t
 2023-06-30 08:37:02.322192 | 2023-06-30 08:37:03.133769 | t
 2023-06-29 16:24:01.705616 | 2023-06-29 16:24:02.55067  | t
 2023-06-29 12:53:33.245688 | 2023-06-29 12:53:34.067159 | t
1 Mi Piace

È interessante. Non l’avevo assolutamente considerato. :slight_smile:

L’aggiunta di un piccolo buffer come AND u.created_at + INTERVAL '1 SECOND' > iu.redeemed_at potrebbe compensare questo aspetto senza influire troppo?

Trovo questo un po’ troppo “magia nera” dato che non sappiamo cosa stia causando il ritardo.

Sospetto che il ritardo sia causato da una grande coda di sidekiq o qualcosa di simile e, sebbene la maggior parte sia inferiore a un secondo, circa il 3% è nell’intervallo 0:00:01 - 0:15:00 (da un secondo a 15 minuti).

E mezzo punto percentuale è nell’ordine dei giorni, il che sembra il tipo di abuso che stiamo cercando di prevenire. Quindi, sebbene questo sia efficace, farebbe più male che bene a causa della quantità di falsi positivi.

2 Mi Piace

Questo dovrebbe risolvere il problema:

1 Mi Piace

Questa sembra più una richiesta di funzionalità diversa piuttosto che un bug. (cc @Falco)

Questo argomento è stato chiuso automaticamente dopo 3 giorni. Non sono più consentite nuove risposte.