Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,8 @@ TEST-**.xml

# Mac OS .DS_Store, which is a file that stores custom attributes of its containing folder
.DS_Store
*.env*
*.env*

# Python artifacts
__pycache__/
*.pyc
3 changes: 1 addition & 2 deletions cogs/alumni_verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import discord
import traceback
from discord.ext import commands
from discord import app_commands
from discord.ui import TextInput, View, Button, Modal
from discord.ui import TextInput, View, Modal
from email_validator import validate_email, EmailNotValidError
from helpers.airtable import get_record_by_email, store_token_by_record, verify_discord_user
from helpers.mail.email_sender import send_verification_SMTP_email
Expand Down
109 changes: 109 additions & 0 deletions cogs/birthday_notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import discord
from discord.ext import commands, tasks
from airtable import Airtable
from datetime import datetime
import os
import config

class BirthdayNotifications(commands.Cog):
def __init__(self, bot):
self.bot = bot
# Initialize Airtable connection
self.api_key = os.getenv('AIRTABLE_API_KEY')
self.base_key = 'appXXXXXXXXXXXXXX' # Replace with your Form base ID
self.table_name = 'Student Membership Application'
self.airtable = Airtable(self.base_key, self.table_name, self.api_key)

# Channel ID for birthday announcements
self.BIRTHDAY_CHANNEL_ID = 245393533391863808 if config.isProd else 1065042153836912714

# Month name to number mapping
self.MONTH_MAP = {
'january': 1, 'february': 2, 'march': 3, 'april': 4,
'may': 5, 'june': 6, 'july': 7, 'august': 8,
'september': 9, 'october': 10, 'november': 11, 'december': 12
}

# Start the birthday check loop
self.birthday_check.start()

def normalize_date(self, date_str):
"""
Normalizes different date formats to datetime object
Handles formats:
- mm-dd-yyyy
- Month DD, YYYY
"""
try:
# Try mm-dd-yyyy format first
if isinstance(date_str, str) and '-' in date_str:
return datetime.strptime(date_str, '%m-%d-%Y')

# Try Month DD, YYYY format
if isinstance(date_str, str) and ',' in date_str:
# Convert "October 25, 1999" to datetime
month, rest = date_str.split(' ', 1)
day, year = rest.replace(',', '').split(' ')
month_num = self.MONTH_MAP[month.lower()]
return datetime(int(year), month_num, int(day))

# If it's already a datetime object
if isinstance(date_str, datetime):
return date_str

raise ValueError(f"Unsupported date format: {date_str}")

except Exception as e:
print(f"Error normalizing date '{date_str}': {str(e)}")
return None

@tasks.loop(time=datetime.time(hour=9)) # Check at 9 AM every day
async def birthday_check(self):
try:
# Get current date (month and day)
today = datetime.now()
current_month = today.month
current_day = today.day

# Fetch all records from Airtable
records = self.airtable.get_all()

for record in records:
fields = record['fields']
if 'Birthday' in fields: # Note: Using 'Birthday' as the column name
birth_date = self.normalize_date(fields['Birthday'])

if birth_date is None:
continue

# Check if it's their birthday
if birth_date.month == current_month and birth_date.day == current_day:
channel = self.bot.get_channel(self.BIRTHDAY_CHANNEL_ID)

if channel:
# Create birthday message embed
embed = discord.Embed(
title="🎉 Happy Birthday! 🎂",
color=discord.Color.brand_green()
)

member_name = fields.get('Full Name', 'Someone')
discord_username = fields.get('Discord Username')

if discord_username:
# Remove any @ symbol if present
discord_username = discord_username.lstrip('@')
embed.description = f"Today is {discord_username}'s birthday! 🎈\nLet's all wish them a wonderful day! 🎊"
else:
embed.description = f"Today is {member_name}'s birthday! 🎈\nLet's all wish them a wonderful day! 🎊"

await channel.send(embed=embed)
except Exception as e:
print(f"Error in birthday check: {str(e)}")

@birthday_check.before_loop
async def before_birthday_check(self):
await self.bot.wait_until_ready()

async def setup(bot):
await bot.add_cog(BirthdayNotifications(bot))
5 changes: 3 additions & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ channels:
- conda-forge
- defaults
dependencies:
- python=3.8
- python>=3.8
- pip
- aiohttp=3.7.4
- async-timeout=3.0.1
Expand All @@ -19,7 +19,7 @@ dependencies:
- multidict=5.1.0
- oauthlib=3.2.2
- pyparsing=3.0.9
- python-dotenv=0.15.0
- python-dotenv
- requests=2.28.2
- requests-oauthlib=1.3.1
- rsa=4.9
Expand Down Expand Up @@ -47,3 +47,4 @@ dependencies:
- pyasn1==0.4.8
- pyasn1-modules==0.2.8
- discord.py
- airtable-python-wrapper