Commit 09401a28 authored by Olivier's avatar Olivier
Browse files

Module 8: send grading assignment to anonymous peers

The code in this commit is contributed by Germán Santa Maria.
parent 087adb49
# -*- coding: utf-8 -*-
"""
Author: Germán Santa Maria
Script: Email Grading Forms
"""
"""-------------------------Hard coded input--------------------------------"""
# Input files paths
input_csv_path = 'script_input/peers.csv'
attachments_path = 'script_input/'
# Output files paths
output_csv_path = 'script_output/sent_emails.csv'
# (Hard-coded email settings)
host="myhost.example.com"
port = 587
sender_email = "sender@example.com"
sender_username = "username"
cc = "cc_address@example.com"
password = input("Type your password and press enter:")
# Delay time between sending two emails, in seconds
# For example, set 240 seconds if you are limited to less than 30 emails/hour
# and 40 seconds if the limit is less than 30 emails/10 min
delay_time = 45
"""-------------------------------------------------------------------------"""
# Import email sender function
import csv # For reading cvs files
import pathlib # For working with local paths
import smtplib, ssl # For email
import time # For timer
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# Initialize arrays to store data
names = [] # Student first name
last_name = [] # Student last name
emails = [] # Student email address
custom_ID_A = [] # Custom ID of the assignment for the student
custom_ID_G = [] # Custom ID of the grading file for the student
ID_G_peer1 = [] # List of peers (ID_G of first peer)
ID_G_peer2 = [] # List of peers (ID_G of second peer)
student_status = [] # True = Student is active; False = Student is not active
attachments = [] # Name of the attachments for each student
email_bodies = [] # Body of the email for each student
text_emails = [] # Array with the complete email text for each student
email_log = [] # Array with the log of successfully sent emails
# Store students data from csv file into variables
with open(input_csv_path, newline='') as f:
student_info_reader = csv.reader(f)
next(student_info_reader) # Skip header [name, last name, email, ...]
student_data = [row for row in student_info_reader]
active_student_data = [] # To store data of the active students only
for row in student_data:
status = row[5] # Status of the student
if status == 'True' or status == 'TRUE':
active_student_data.append(row)
# Store active student's data in arrays
for row in active_student_data:
names.append(row[0])
last_name.append(row[1])
emails.append(row[2])
custom_ID_A.append(row[3])
custom_ID_G.append(row[4])
student_status.append(row[5])
ID_G_peer1.append(row[6])
ID_G_peer2.append(row[7])
# Generate list of attachments for each student
for i in range(len(emails)):
attachment_peer1 = ID_G_peer1[i] + ".pdf"
attachment_peer2 = ID_G_peer2[i] + ".pdf"
# Attachments list for each student
student_attachments = [attachment_peer1, attachment_peer2]
# Append students attachments to full list of attachments to be mailed
attachments.append(student_attachments)
# Make sure that all the attachments are in the script_input folder by looking
# for a file with the correct file name
print('Checking attachments...')
for row in attachments:
for file in row:
file_to_search = pathlib.Path(attachments_path+file)
if file_to_search.exists() != True:
raise Exception('The file ' + str(file) +
' was not found, no emails were sent')
print('All the attachments were found in the input folder')
print(' ')
"""-----------------Build email text for each student-----------------------"""
# Write a personalized email body for each student
standard_body = """Dear XXstudent_firstnameXX,
congratulations for submitting your first coursework assignment!
Here is now the following part, where you are going to grade two of your peers.
(insert email body here)
%%% How to submit %%%
Attached, you will find two anonymized submissions from peer students, bundled with grading information. At the end of each document, there is a form. Please fill in the form following the included grading guidelines.
Once you are done, save both files, keeping their file name unchanged, and send them back to this address.
(insert email body here)
With best regards,
(author)
""" # End of email body
# Replace markers in the email body for each student
for i in range(0, len(names)):
# Replace student name in the email body marker
temp_body = standard_body.replace("XXstudent_firstnameXX", names[i])
# Save email body to array
email_bodies.append(temp_body)
# Compose email text for each student
for i in range(0, len(names)):
# Reciever email
receiver_email = emails[i]
# Email subject
subject = email_subject
# Email body
body = email_bodies[i]
# Attachments
filenames = attachments[i]
# Set headers
message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject
message["Cc"] = cc
# Add body to email
message.attach(MIMEText(body, "plain"))
# Add attachments
for filename in filenames:
attachment_path = attachments_path + filename # Attachment folder path
# Open PDF file in binary mode
with open(attachment_path, "rb") as attachment:
# Add file as application/octet-stream
part = MIMEBase("application", "octet-stream")
part.set_payload(attachment.read())
# Encode file in ASCII characters to send by email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header("Content-Disposition",
f"attachment; filename= {filename}",)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
text_emails.append(text)
"""-------------------------------------------------------------------------"""
# Send an email to each student with the corresponding attachment
"""------------------------------Send emails--------------------------------"""
# Create a secure SSL context
context = ssl.create_default_context()
# Check if the login data is correct
try :
server = smtplib.SMTP(host = host, port = port)
server.starttls(context = context) #Encryption
server.login(sender_username, password)
print('Login to: '+ sender_email + ' was successful ')
except Exception as e:
# Print error message
print('Login to: '+ sender_email +
' was not successful, no emails were sent ')
raise Exception(e)
server.close() # Logout
# Send email to each student
for i in range(0, len(names)):
try :
# Reciever email
receiver_email = emails[i]
# Email content
text = text_emails[i]
# Logging into email server
server = smtplib.SMTP(host = host, port = port)
server.starttls(context = context) #Encryption
server.login(sender_username, password)
# Send email
server.sendmail(sender_email, [receiver_email, cc], text)
# Logout
server.close() # Logout
# Print email log
local_time = time.time()
time_sent = time.ctime(local_time)
log_m = 'Email was sent to: ' + receiver_email + ' time: ' + time_sent
print(log_m)
except Exception as e:
# Print error
log_m = 'Error while trying to send email to: ' + receiver_email
print(log_m)
print(e)
log_m = 'Email could not be sent, error: ' + str(e)
# Save log
email_log.append(log_m)
# Wait before sending the next email
time.sleep(delay_time)
# Store email log in a csv file
with open (output_csv_path,'w',newline='') as f:
writer = csv.writer(f)
writer.writerow(['name','lastname','email','custom_ID_A','custom_ID_G',
'log'])
for i in range(0,len(names)):
writer.writerow([names[i],last_name[i],emails[i],custom_ID_A[i],
custom_ID_G[i], email_log[i]])
"""-------------------------------------------------------------------------"""
# End of the script
#!/bin/bash
# Input parameters
inputfolder='script_input-real'
outputfolder='script_output-real'
timestamp=$(date "+%Y-%m-%d+%H%M%S")
outputbackupname="backup_output_$timestamp.tar"
inputbackupname="backup_input_$timestamp.tar"
# Create archive of output folder
mkdir -vp archives
tar -cvf $outputbackupname --exclude=old $outputfolder
mv -vf $outputbackupname archives/
tar -cvf $inputbackupname --exclude=old $inputfolder
mv -vf $inputbackupname archives/
# Import output of M7 and M5 into input of M8
rsync -avh --delete ../M7_generate_grading/script_output/done/ $inputfolder/pdfs/
rsync -avh --delete ../M6_match_peers/script_output/peers.csv $inputfolder/
# Clear output folder
rm -rvf $outputfolder/*
echo "end of script."
......@@ -44,7 +44,7 @@ A total of ten modules (eight of which being locally-run scripts) are needed to
[x] [Module 7](M7_generate_grading): Generate grading assignments
(in bash, with pdftk)
[ ] Module 8: Send peer grading assignments
[x] [Module 8](M8_send_grading): Send peer grading assignments
(in Python)
[ ] Module 9: Process grades
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment