Compare commits
3 Commits
0d9f5264d4
...
2f3f1d9a13
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f3f1d9a13 | |||
| 541b947609 | |||
| 598bae34ba |
66
src/draw.py
66
src/draw.py
@ -1,41 +1,51 @@
|
||||
from random import choice
|
||||
|
||||
def draw_names(previous_draw, draws_per_person):
|
||||
def draw_names(current_participants, history_data, draws_per_person, max_attempts=5):
|
||||
"""
|
||||
Perform the Secret Santa draw considering past draws.
|
||||
:param previous_draw: Last year's draw data (list of participants and recipients).
|
||||
Perform the Secret Santa draw considering past years' draws.
|
||||
:param current_participants: This year's participant list.
|
||||
:param history_data: Historical draw data to avoid repeats.
|
||||
:param draws_per_person: Number of people each participant should give gifts to.
|
||||
:param max_attempts: Maximum number of retry attempts before loosening exclusions. by default : 5.
|
||||
:return: The new draw results.
|
||||
"""
|
||||
participants = [a[0] for a in previous_draw] # Get participant names
|
||||
participants = [p[0] for p in current_participants] # Get participant names
|
||||
already_drawn = [] # Track who has been drawn
|
||||
new_draw = [] # Store new draw results
|
||||
|
||||
for i in range(len(participants)):
|
||||
giver = previous_draw[i][0]
|
||||
email = previous_draw[i][1]
|
||||
print(email)
|
||||
last_year_r1 = previous_draw[i][2]
|
||||
last_year_r2 = previous_draw[i][3]
|
||||
for attempt in range(max_attempts):
|
||||
new_draw.clear()
|
||||
already_drawn.clear()
|
||||
success = True # Track if draw is successful in this attempt
|
||||
|
||||
available_participants = participants.copy()
|
||||
try:
|
||||
available_participants.remove(giver)
|
||||
available_participants.remove(last_year_r1)
|
||||
available_participants.remove(last_year_r2)
|
||||
except ValueError:
|
||||
pass
|
||||
for i, giver in enumerate(participants):
|
||||
email = current_participants[i][1]
|
||||
# Collect previous recipients to avoid drawing the same person again
|
||||
previous_recipients = {recipient for record in history_data if record[0] == giver for recipient in record[2:]}
|
||||
|
||||
new_recipients = []
|
||||
while len(new_recipients) < draws_per_person:
|
||||
selected = choice(available_participants)
|
||||
if already_drawn.count(selected) >= draws_per_person:
|
||||
available_participants.remove(selected)
|
||||
else:
|
||||
new_recipients.append(selected)
|
||||
already_drawn.append(selected)
|
||||
available_participants.remove(selected)
|
||||
# Create a set of available participants excluding the giver and previous recipients
|
||||
available_participants = set(participants) - {giver} - previous_recipients
|
||||
new_recipients = []
|
||||
|
||||
new_draw.append([giver, email] + new_recipients)
|
||||
# Ensure there are enough available participants for the draw
|
||||
if len(available_participants) < draws_per_person:
|
||||
success = False
|
||||
break
|
||||
|
||||
return new_draw
|
||||
# Select recipients for the current giver
|
||||
while len(new_recipients) < draws_per_person:
|
||||
selected = choice(list(available_participants))
|
||||
if already_drawn.count(selected) < draws_per_person:
|
||||
new_recipients.append(selected)
|
||||
already_drawn.append(selected)
|
||||
available_participants.discard(selected)
|
||||
|
||||
new_draw.append([giver, email] + new_recipients)
|
||||
|
||||
# If the draw was successful, break out of attempts
|
||||
if success:
|
||||
return new_draw
|
||||
print(f"Attempt {attempt + 1} failed, retrying...")
|
||||
|
||||
# If all attempts fail, raise an error
|
||||
raise ValueError("Unable to complete a valid draw after maximum attempts.")
|
||||
|
||||
@ -1,13 +1,57 @@
|
||||
import csv
|
||||
from datetime import date
|
||||
from env import CSV_PREFIX, CSV_PATH
|
||||
|
||||
def open_csv(file_name):
|
||||
"""Open the CSV file and return its contents as a list of rows"""
|
||||
with open(file_name, "r", encoding='utf-8') as file:
|
||||
reader = csv.reader(file)
|
||||
return list(reader)
|
||||
def load_history(years):
|
||||
"""
|
||||
Load participant data from multiple CSV files based on the specified history years.
|
||||
:param years: Number of years of history to load.
|
||||
:return: A list of all historical draw data.
|
||||
"""
|
||||
current_year = date.today().year
|
||||
history_data = []
|
||||
|
||||
def save_csv(data, file_name):
|
||||
"""Save the updated draw results to the CSV file"""
|
||||
# Load data for each of the past specified years
|
||||
for i in range(1, years + 1):
|
||||
|
||||
try:
|
||||
year = current_year - i
|
||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{year}.csv"
|
||||
with open(file_name, "r", encoding='utf-8') as file:
|
||||
reader = csv.reader(file)
|
||||
history_data.extend(list(reader)) # Add each year's data
|
||||
except FileNotFoundError:
|
||||
print(f"No historical file found for year {year}, skipping.")
|
||||
continue
|
||||
|
||||
return history_data
|
||||
|
||||
def load_participants():
|
||||
"""
|
||||
Load participant data from the current year CSV file.
|
||||
:return: A list of all historical draw data.
|
||||
"""
|
||||
current_year = date.today().year
|
||||
participants_data = []
|
||||
try:
|
||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{current_year}.csv"
|
||||
print(file_name)
|
||||
with open(file_name, "r", encoding='utf-8') as file:
|
||||
reader = csv.reader(file)
|
||||
participants_data.extend(list(reader)) # Add each year's data
|
||||
except FileNotFoundError:
|
||||
print(f"No file found for year {current_year}, skipping.")
|
||||
|
||||
|
||||
return participants_data
|
||||
|
||||
def save_csv(data, year):
|
||||
"""
|
||||
Save the new draw results to a CSV file named with the current year.
|
||||
:param data: New draw data.
|
||||
:param year: The current year for naming the file.
|
||||
"""
|
||||
file_name = f"{CSV_PATH}/{CSV_PREFIX}_{year}.csv"
|
||||
with open(file_name, 'w', newline='', encoding='utf-8') as file:
|
||||
writer = csv.writer(file)
|
||||
writer.writerows(data)
|
||||
22
src/main.py
22
src/main.py
@ -1,5 +1,5 @@
|
||||
from env import CSV_FILE_PATH, DRAW_PER_PERSON, EMAIL_SUBJECT, EMAIL_BODY
|
||||
from file_io import open_csv, save_csv
|
||||
from env import DRAW_PER_PERSON, HISTORY_YEARS, EMAIL_SUBJECT, EMAIL_BODY
|
||||
from file_io import load_history, save_csv, load_participants
|
||||
from draw import draw_names
|
||||
from emailer import send_email
|
||||
from utils import get_current_time
|
||||
@ -11,29 +11,29 @@ def send_all_emails(new_draw):
|
||||
for participant in new_draw:
|
||||
name = participant[0]
|
||||
receiver_email = participant[1]
|
||||
draws = ", ".join(participant[2:]) # List of recipients
|
||||
draws = ", ".join(participant[2:])
|
||||
message = EMAIL_BODY.format(name=name, draws=draws)
|
||||
subject = EMAIL_SUBJECT.format(year=current_year)
|
||||
send_email(receiver_email, subject, message) # Send the email
|
||||
send_email(receiver_email, subject, message)
|
||||
print(f"Email sent to {name} ({receiver_email})")
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
# Load previous draw data
|
||||
old_draw = open_csv(CSV_FILE_PATH)
|
||||
# Load data from historical CSVs and this year's participants
|
||||
history_data = load_history(HISTORY_YEARS)
|
||||
|
||||
# Perform new draw
|
||||
new_draw = draw_names(old_draw, DRAW_PER_PERSON)
|
||||
current_year = date.today().year
|
||||
current_participants = load_participants() # Load participants data
|
||||
|
||||
# Perform the draw
|
||||
new_draw = draw_names(current_participants, history_data, DRAW_PER_PERSON)
|
||||
# Send emails to participants
|
||||
send_all_emails(new_draw)
|
||||
|
||||
# Save new draw results
|
||||
save_csv(new_draw, CSV_FILE_PATH)
|
||||
save_csv(new_draw, current_year)
|
||||
|
||||
# Output completion time
|
||||
print(f"Process completed at {get_current_time()[1]} on {get_current_time()[0]}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error occurred: {e}")
|
||||
# Retry or handle errors
|
||||
|
||||
Loading…
Reference in New Issue
Block a user