Add all code and readme

This commit is contained in:
Paul Gonçalves Monnet 2024-10-18 16:30:19 +02:00
parent 19522c8615
commit 56e123b237
8 changed files with 246 additions and 1 deletions

1
.gitignore vendored
View File

@ -160,3 +160,4 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
config/env.py

126
README.md
View File

@ -1,2 +1,126 @@
# Random-Christmass-Bot
# Random Christmas Bot
This Python project automates the process of organizing a Secret Santa event. It randomly assigns each participant one or two recipients and ensures participants do not receive the same recipients from the previous year. The results are sent via email using an SMTP relay, and participant data (names, emails, and previous draw results) are managed in a CSV file.
## Features
- Randomly assign one or two recipients for each participant.
- Ensure participants do not receive the same recipients as last year.
- Sends personalized emails with draw results to participants.
- Stores participant data (names, emails, and draw results) in a CSV file.
- Modular structure for better code maintenance.
- All key parameters are configurable in a separate configuration file (`env.py`).
## Project Structure
```bash
secret-santa/
├── config/
│ └── env.py # Configuration settings (SMTP, file paths, etc.)
├── src/
│ ├── draw.py # Logic for drawing names
│ ├── emailer.py # Email sending functionality
│ ├── file_io.py # File handling (CSV reading/writing)
│ ├── main.py # Main program logic
│ └── utils.py # Utility functions (date, time handling)
└── README.md # Project readme
```
### `config/env.py`
The configuration file contains SMTP settings, file paths, and customizable parameters for the draw.
Example `env.py`:
```python
SMTP_SERVER = "smtp.example.com"
SMTP_PORT = 25
SENDER_EMAIL = "santa@example.com"
CSV_FILE_PATH = "secret_santa_DB.csv"
DRAW_PER_PERSON = 2 # Choose 1 or 2 recipients per person
# Email content
EMAIL_SUBJECT = "Secret Santa {year} Draw"
EMAIL_BODY = """
Hello {name},
You have been chosen to give gifts to: {draws}.
Feel free to use your imagination and make their Christmas magical!
Merry Christmas!
This email was sent automatically, please do not reply.
"""
```
## Requirements
- Python 3.x
- SMTP server (relay, no authentication required)
- `smtplib` for sending emails (Python's built-in library)
- CSV file to store participant data
## Installation
1. Clone the repository or download the script files.
2. Ensure you have Python installed on your system. If not, download and install Python from [here](https://www.python.org/downloads/).
3. Set up the `env.py` file in the `config/` directory, adjusting the SMTP settings, CSV file path, and draw parameters as needed.
Example structure of the CSV file:
```csv
Name,Email,Last_Year_Recipient_1,Last_Year_Recipient_2
Alice,alice@example.com,Bob,Charlie
Bob,bob@example.com,Alice,David
Charlie,charlie@example.com,David,Alice
```
4. Ensure the CSV file is in the correct location as specified in `env.py`.
## Usage
1. Run the main script by executing:
```bash
python src/main.py
```
2. The script will:
- Load participant data from the CSV file.
- Perform the Secret Santa draw based on the configuration (1 or 2 recipients).
- Send an email to each participant with the names of their gift recipients.
- Save the updated draw results back to the CSV file.
3. If any errors occur, they will be displayed in the console, and you can retry or debug as needed.
## Customization
- **Number of recipients**: Modify `DRAW_PER_PERSON` in `env.py` to choose whether participants receive one or two recipients.
- **Email content**: Customize the email subject and body in `env.py` using placeholders like `{name}` for the participant's name and `{draws}` for their recipients.
- **CSV file location**: Adjust the `CSV_FILE_PATH` in `env.py` if you prefer a different directory for the participant data.
## File Descriptions
- **`draw.py`**: Contains the logic for performing the Secret Santa draw, ensuring no repeat recipients from last year.
- **`emailer.py`**: Handles email sending via the SMTP server.
- **`file_io.py`**: Responsible for reading and writing the participant data from/to the CSV file.
- **`main.py`**: The main program that ties everything together and coordinates the draw and email sending.
- **`utils.py`**: Utility functions, such as fetching the current date and time.
## Notes
- The project assumes an SMTP server that does not require authentication. If authentication is needed, the script can be extended to support login.
- The project should be run once per year before the holiday season.
- Manually update the CSV file each year with any new participants.
## License
This project is licensed under the MIT License. You are free to modify and distribute the script as needed.
## Contributions
Contributions are welcome! Feel free to open issues or submit pull requests to improve this project.

View File

40
src/draw.py Normal file
View File

@ -0,0 +1,40 @@
from random import choice
def draw_names(previous_draw, draws_per_person):
"""
Perform the Secret Santa draw considering past draws.
:param previous_draw: Last year's draw data (list of participants and recipients).
:param draws_per_person: Number of people each participant should give gifts to.
:return: The new draw results.
"""
participants = [a[0] for a in previous_draw] # Get participant names
already_drawn = [] # Track who has been drawn
new_draw = [] # Store new draw results
for i in range(len(participants)):
last_year_r1 = previous_draw[i][2]
last_year_r2 = previous_draw[i][3]
giver = previous_draw[i][0]
email = previous_draw[i][1]
available_participants = participants.copy()
try:
available_participants.remove(giver)
available_participants.remove(last_year_r1)
available_participants.remove(last_year_r2)
except ValueError:
pass
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)
new_draw.append([giver, email] + new_recipients)
return new_draw

20
src/emailer.py Normal file
View File

@ -0,0 +1,20 @@
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from config.env import SMTP_SERVER, SMTP_PORT, SENDER_EMAIL
def send_email(receiver_email, subject, msg):
"""
Send an email using a simple SMTP relay without authentication.
:param receiver_email: The recipient's email address.
:param subject: The email subject.
:param msg: The email body content.
"""
message = MIMEMultipart()
message['From'] = SENDER_EMAIL
message['To'] = receiver_email
message['Subject'] = subject
message.attach(MIMEText(msg, 'plain'))
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.sendmail(SENDER_EMAIL, receiver_email, message.as_string())

13
src/file_io.py Normal file
View File

@ -0,0 +1,13 @@
import csv
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 save_csv(data, file_name):
"""Save the updated draw results to the CSV file"""
with open(file_name, 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(data)

39
src/main.py Normal file
View File

@ -0,0 +1,39 @@
from config.env import CSV_FILE_PATH, DRAW_PER_PERSON, EMAIL_SUBJECT, EMAIL_BODY
from src.file_io import open_csv, save_csv
from src.draw import draw_names
from src.emailer import send_email
from src.utils import get_current_time
from datetime import date
def send_all_emails(new_draw):
"""Send the Secret Santa draw results to all participants via email."""
current_year = date.today().year
for participant in new_draw:
name = participant[0]
receiver_email = participant[1]
draws = ", ".join(participant[2:]) # List of recipients
message = EMAIL_BODY.format(name=name, draws=draws)
subject = EMAIL_SUBJECT.format(year=current_year)
send_email(receiver_email, subject, message) # Send the email
print(f"Email sent to {name} ({receiver_email})")
if __name__ == "__main__":
try:
# Load previous draw data
old_draw = open_csv(CSV_FILE_PATH)
# Perform new draw
new_draw = draw_names(old_draw, DRAW_PER_PERSON)
# Send emails to participants
send_all_emails(new_draw)
# Save new draw results
save_csv(new_draw, CSV_FILE_PATH)
# 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

8
src/utils.py Normal file
View File

@ -0,0 +1,8 @@
from datetime import date
import time
def get_current_time():
""" Return the current date and time """
today = date.today()
current_time = time.strftime("%H:%M:%S", time.localtime())
return today.strftime("%d/%m/%Y"), current_time