1 GrumpyBirthdays EN
darksoon edited this page 2026-07-11 01:05:01 +02:00

Birthdays — Birthday Congrats & Role

GrumpyBirthdays lets every user store their birth date. On the day itself, the bot automatically posts a congrats message and can optionally assign a temporary "birthday" role.


Activation

In configs/config.yml:

addons:
  birthdays: true

On first start, configs/modules/birthdays.yml is created.


birthdays.yml

enabled: true

channelId: ""      # Channel for the congrats message. "" = nothing is posted
roleId: ""         # Role assigned on the birthday. "" = no role assignment

message: "🎉 Happy Birthday {{user}}! 🎂"
# Placeholder: {{user}} is replaced with a mention

Commands

/birthday set <date>

Sets (or overwrites) your own birth date.

Option Description
date Format DD.MM, e.g. 24.12 (DD-MM or DD/MM are also accepted)
/birthday set date:24.12

The year is not stored — only day and month.


/birthday remove

Removes your own stored birthday.

/birthday remove

Fails (with an error message) if no birthday is set.


/birthday upcoming

Shows all birthdays in the next 30 days, sorted by proximity.

/birthday upcoming

Format per line: @User — DD.MM · in X day(s), or 🎉 today! on the day itself.


/birthday reload

Reloads birthdays.yml without restarting the bot.

/birthday reload

Permission: Manage Guild


Flow: Congrats Post & Role Assignment

An hourly runner (not daily!) checks whether anyone has a birthday today (UTC).

Why hourly instead of once a day? A bot restart exactly at midnight UTC would completely miss the window with a daily check. The hourly check self-corrects quickly.

Per due birthday (today, not yet congratulated this year):

  1. If channelId is set → the congrats message is posted there (message with {{user}} replaced).
  2. If roleId is set → the role is assigned to the member.
  3. The user is marked as "already congratulated this year" (lastCongratsYear) — even if the post or role assignment fails (e.g. due to a missing permission). This avoids retrying every hour against a broken setup; the role cleanup logic (see below) corrects it the following day regardless.

Role cleanup (the following day): Anyone who received the birthday role on a past day this year but no longer has a birthday today loses the role again — so it doesn't linger permanently.

Hourly tick
  ├─ Due birthdays today (not yet congratulated this year)
  │    ├─ post in channelId (if set)
  │    ├─ assign role roleId (if set)
  │    └─ mark as "congratulated" (best effort, even on failure)
  └─ Expired role holders (congratulated, but no longer a birthday today)
       └─ remove the role again

Leap Year Handling (February 29)

February 29 is allowed as a valid date — the bot simply stores month: 2, day: 29. Since the due-date check (findDueToday) is based on the actual current UTC date, this birthday only fires in leap years, when February 29 actually exists. There is no automatic fallback day (e.g. March 1) in non-leap years — the congrats simply doesn't happen that year.


Permissions

Command Permission
/birthday set Everyone
/birthday remove Everyone (own entry only)
/birthday upcoming Everyone
/birthday reload Manage Guild

For automatic role assignment, the bot needs Manage Roles, and its own role must be above the birthday role in the hierarchy. All commands are guild-only (no DM context).