"""
A couple of functons which automates everything.
:githublink:`%|py|5`
"""
import os
import pandas
from pyquickhelper.loghelper import fLOG
from pyquickhelper.filehelper import encrypt_stream
from pymmails import MailBoxImap, EmailMessageRenderer, EmailMessageListRenderer
from pymmails.render.email_message_style import template_email_html_short
from .projects_repository import ProjectsRepository
from .mail_helper import grab_addresses
[docs]def extract_students_mails_from_gmail_and_stores_in_folders(folder=".", filemails="emails.txt",
user=None, pwd=None, server="imap.gmail.com",
mailfolder=[
"ensae/ENSAE_2016_3A"],
date="1-Jan-2016", zipfilename="projet_3A_2016.zip",
zipencpwd=b"sixteenbyteskeys", dataframe=None,
columns={
"name": "nom_prenom", "group": "groupe", "subject": "sujet"},
skip_names=None, process_name=None,
title="List of emails", nolink_if=None, fLOG=fLOG):
"""
The scenario is the following:
* You are the teacher.
* Students started their projects at date *t*.
* They can work alone or by group.
* They send mails, you reply.
* Their address mail follows the convention: ``<first name>.<last name>@anything``
so it is to associate a mail address to a student name.
* You move every mail you received in a separate folder in your inbox.
* Sometime, you send a mail to everybody.
* Finally they send their project with attachments.
* You want to store everything (mails and attachements) in folders, one per group.
* You want a summary of what was received.
* You want to build a zip file to share their work with others teachers.
* You want to update the folder if a new mail was sent.
This function looks into a folder of your inbox and grabs every mails and
attachements from a groups of students.
:param folder: where to store the results
:param filemails: files used to store students address,
the operation is done once, remove the file
to force the function to rebuild the information.
:param user: user of the gmail inbox
:param pwd: password of the gmail inbox
:param server: gmail server, it should be ``"imap.gmail.com"``,
it works with others mail servers using the *IMAP* protocol
:param mailfolder: folder in your inbox to look into,
there can be several
:param date: when to start looking (do not change the format,
look at the default value)
:param zipfilename: name of the zip file to create
:param zipencpwd: the zip file is also encrypted for a safer share with this key
and function `encrypt_stream <http://www.xavierdupre.fr/app/pyquickhelper/helpsphinx/
pyquickhelper/filehelper/encryption.html#pyquickhelper.filehelper.encryption.encrypt_stream>`_.
:param dataframe: dataframe which contains the definition of students groups
:param columns: columns the function will look into, students names, group definition
(a unique number for all students in the same group), subject
:param skip_names: list of names to skip
:param process_name: to operate a transformation before matching students names with
their emails
:param title: each group folder contains a html file connecting them,
this is its title
:param nolink_if: The summary extracts links from url, it skips the urls which
contains on the substrings included in that list (None to use a default set)
:param fLOG: logging function
:return: :class:`ProjectsRepository <ensae_teaching_cs.automation_students.projects_repository.ProjectsRepository>`
By default, Gmail does not let you programmatically access you own inbox,
you need to modify your gmail parameters to let this function do so.
:githublink:`%|py|77`
"""
folder = os.path.abspath(".")
filemails = os.path.join(folder, filemails)
zipfilename = os.path.join(folder, zipfilename)
zipfilenameenc = zipfilename + ".enc"
# load the groups
if isinstance(dataframe, pandas.DataFrame):
df = dataframe
elif dataframe.endswith("xlsx"):
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] read dataframe", dataframe)
df = pandas.read_excel(dataframe, engine='openpyxl')
else:
df = pandas.read_csv(dataframe, sep="\t", encoding="utf8")
# check mails
if "mail" not in columns:
if os.path.exists(filemails):
fLOG(
"[extract_students_mails_from_gmail_and_stores_in_folders] read addresses from ", filemails)
with open(filemails, "r", encoding="utf8") as f:
lines = f.readlines()
emails = [li.strip("\r\t\n ") for li in lines]
else:
fLOG(
"[extract_students_mails_from_gmail_and_stores_in_folders] mine address ")
box = MailBoxImap(user, pwd, server, ssl=True, fLOG=fLOG)
box.login()
emails = grab_addresses(box, mailfolder, date, fLOG=fLOG)
box.logout()
with open(filemails, "w", encoding="utf8") as f:
f.write("\n".join(emails))
else:
# nothing to do mail already present
emails = set(df[columns["mail"]])
# we remove empty names
df = df[~df[columns["name"]].isnull()].copy()
if process_name:
df[columns["name"]] = df[columns["name"]].apply(
lambda f: process_name(f))
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] create groups folders in", folder)
proj = ProjectsRepository(folder, fLOG=fLOG)
proj = ProjectsRepository.create_folders_from_dataframe(df, folder,
col_subject=columns[
"subject"], fLOG=fLOG, col_group=columns["group"],
col_student=columns[
"name"], email_function=emails, skip_if_nomail=False,
col_mail=columns["mail"], must_have_email=True, skip_names=skip_names)
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] nb groups", len(
proj.Groups))
# gathers mails
email_renderer = EmailMessageRenderer(tmpl=template_email_html_short,
fLOG=fLOG)
renderer = EmailMessageListRenderer(title=title, email_renderer=email_renderer,
fLOG=fLOG)
box = MailBoxImap(user, pwd, server, ssl=True, fLOG=fLOG)
box.login()
proj.dump_group_mails(renderer, group=None, mailbox=box, subfolder=mailfolder,
date=date, overwrite=False, skip_if_empty=True)
box.logout()
# cleaning files
for group in proj.Groups:
files = list(proj.enumerate_group_files(group))
att = [_ for _ in files if ".html" in _]
if len(att) <= 1:
fLOG(
"[extract_students_mails_from_gmail_and_stores_in_folders] remove '{}'".format(group))
proj.remove_group(group)
# unzip files and convert notebooks
for group in proj.Groups:
proj.unzip_convert(group)
summary = os.path.join(folder, "index.html")
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] write summary '{}'".format(summary))
if os.path.exists(summary):
os.remove(summary)
proj.write_run_command()
proj.write_summary(nolink_if=nolink_if)
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] zip everything in", zipfilename)
if os.path.exists(zipfilename):
os.remove(zipfilename)
proj.zip_group(None, zipfilename,
addition=["index.html", "mail_style.css", "emails.txt"])
fLOG("[extract_students_mails_from_gmail_and_stores_in_folders] encrypt the zip file in '{}'.".format(
zipfilenameenc))
if os.path.exists(zipfilenameenc):
os.remove(zipfilenameenc)
encrypt_stream(zipencpwd, zipfilename, zipfilenameenc, chunksize=2 ** 30)
return proj