# Отзыв бейджа нижнего уровня при получении более высокого?

**URL:** https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542
**Category:** Data & reporting
**Tags:** sql-triggered-badge
**Created:** [05.Июль.2022 14:59:03 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542 "2022-07-05T14:59:03Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![rapphann](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rapphann/32/259509_2.png) [@rapphann](https://meta.discourse.org/u/rapphann)
#### Post date: [05.Июль.2022 14:59:03 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/1 "2022-07-05T14:59:03Z")

</div>

Как исключить права на получение значка нижнего уровня, если уже выдан значок более высокого уровня? Цель — выдавать пользователю только значок наивысшего уровня, на который он имеет право…

Предположим, у меня есть 3 значка:

Уровень 1: 5 отданных лайков, 5 полученных  
Уровень 2: 100 отданных лайков, 100 полученных  
Уровень 3: 250 отданных лайков, 250 полученных

Ниже приведен код для Уровня 2. Для других уровней нет никаких отличий, кроме числа ‘100’

```plaintext
SELECT us.user_id, current_timestamp AS granted_at 
FROM user_stats AS us
WHERE us.likes_received >= 100 
AND us.likes_given >= 100
AND (:backfill OR us.user_id IN (:user_ids))

```

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [05.Июль.2022 23:34:04 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/2 "2022-07-05T23:34:04Z")

</div>

В настройках `/admin/badges/BADGE-ID` просто отметьте опцию `Запускать запрос на отзыв ежедневно`. Значок будет удален, если пользователи перестанут соответствовать критериям SQL.

> ![image](https://global.discourse-cdn.com/meta/original/4X/b/0/2/b02ec69d0aeff3cd4482f82dfc32ad53999aab35.png)

Также рекомендуется включить опцию `Обновлять ежедневно`, чтобы выдача и отзыв происходили примерно в одно и то же время (около полуночи по местному времени вашего экземпляра, насколько я помню).

---

<div class="post-metadata">

### Author: ![rapphann](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rapphann/32/259509_2.png) [@rapphann](https://meta.discourse.org/u/rapphann)
#### Post date: [06.Июль.2022 02:30:52 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/3 "2022-07-06T02:30:52Z")

</div>

Спасибо, Натан. Я посмотрю.

---

<div class="post-metadata">

### Author: ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)
#### Post date: [06.Июль.2022 08:04:29 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/4 "2022-07-06T08:04:29Z")

</div>

Не потребуется ли здесь также дополнительная строка в SQL для бейджа, чтобы сбалансировать его? Что-то вроде:

```plaintext
SELECT us.user_id, current_timestamp AS granted_at 
FROM user_stats AS us
WHERE us.likes_received >= 100 
AND us.likes_given >= 100
AND us.likes_given < 250
AND (:backfill OR us.user_id IN (:user_ids))

```

(возможно, использовать BETWEEN или аналогичное условие, хотя я пока не тестировал это 🙂)

И тогда при выполнении запроса бейдж за 100 лайков будет выдан в первый раз, пропущен для значений от 101 до 249, а затем отозван при достижении 250 (где следующий бейдж продолжит отсчёт).

* * *

**Обновление:** Я немного поэкспериментировал с `BETWEEN`, и что-то вроде этого, похоже, правильно определяет всех нужных пользователей в тестовом образце:

```plaintext
SELECT us.user_id
FROM user_stats AS us
WHERE us.likes_received BETWEEN 100 AND 249 
ORDER BY us.likes_received DESC

```

Так что что-то вроде этого должно сработать, если преобразовать в триггерный бейдж:

```plaintext
SELECT us.user_id, current_timestamp AS granted_at 
FROM user_stats AS us
WHERE us.likes_received BETWEEN 100 AND 249
AND us.likes_given BETWEEN 100 AND 249
AND (:backfill OR us.user_id IN (:user_ids))

```

---

<div class="post-metadata">

### Author: ![rapphann](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rapphann/32/259509_2.png) [@rapphann](https://meta.discourse.org/u/rapphann)
#### Post date: [09.Июль.2022 15:37:16 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/5 "2022-07-09T15:37:16Z")

</div>

Это почти идеально. Может произойти одно редкое событие: пользователь превышает лимит в ‘given’, но отстает в ‘received’ (или наоборот), из-за чего значок может быть отозван до получения следующего (процедура отзыва).

Я изучил ситуацию и обнаружил интересное свойство: `something.badge_id = 123`, где ‘something’ — переменная, определенная пользователем, а ‘123’ — идентификатор другого значка. Я попробую дополнить исходные SQL-запросы для уровня 1 и уровня 2 проверками на дисквалификацию в отношении значков более высокого уровня.

---

<div class="post-metadata">

### Author: ![JammyDodger](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/jammydodger/32/254611_2.png) [@JammyDodger](https://meta.discourse.org/u/JammyDodger)
#### Post date: [09.Июль.2022 15:51:49 UTC](https://meta.discourse.org/t/revoking-a-lower-tier-badge-when-a-higher-one-is-achieved/281542/6 "2022-07-09T15:51:49Z")

</div>

> [@rapphann](#):
>
> Это почти идеально. Может произойти одно редкое событие: пользователь перевыполняет «данное», но отстает по «полученному» (или наоборот), поэтому значок может быть отозван до выдачи следующего (процедура отзыва).

Это очень интересный момент, о котором я не подумал. 🙂 Двойственная природа действительно делает ситуацию немного более щекотливой. 🤔

Мне нравится идея добавить проверку на наличие других значков, это может быть полезно.
