diff --git a/notebooks/pyconde-pydata-darmstadt-2025/20_mail_to_reviewers_v1.ipynb b/notebooks/pyconde-pydata-darmstadt-2025/20_mail_to_reviewers_v1.ipynb new file mode 100644 index 0000000..126e651 --- /dev/null +++ b/notebooks/pyconde-pydata-darmstadt-2025/20_mail_to_reviewers_v1.ipynb @@ -0,0 +1,912 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import math\n", + "import logging\n", + "import structlog\n", + "from pathlib import Path\n", + "\n", + "import tomli\n", + "import numpy as np\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import matplotlib as mpl\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "%config InlineBackend.figure_format = 'retina'\n", + "\n", + "import seaborn as sns\n", + "sns.set_context(\"poster\")\n", + "sns.set(rc={\"figure.figsize\": (16, 9.)})\n", + "sns.set_style(\"whitegrid\")\n", + "\n", + "import pandas as pd\n", + "pd.set_option(\"display.max_rows\", 120)\n", + "pd.set_option(\"display.max_columns\", 120)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Set the logging level\n", + "logging.basicConfig(level=logging.INFO, stream=sys.stdout)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pytanis\n", + "from pytanis import GSheetsClient, PretalxClient, HelpDeskClient\n", + "from pytanis.review import Col\n", + "from pytanis.mailgun import Mail, Recipient, MailClient" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Be aware that this notebook might only run with the following version\n", + "pytanis.__version__ " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Import event-specific settings to don't have them here in the notebook\n", + "with open('config.toml', 'rb') as fh:\n", + " cfg = tomli.load(fh)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Get all the Reviewers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "gsheet_client = GSheetsClient()\n", + "gsheet_df = gsheet_client.gsheet_as_df(cfg['reviewer_spread_id'], cfg['reviewer_work_name'])\n", + "# rename columns to stick to our convention\n", + "col_map = {\n", + " \"Topics you want to review\": Col.track_prefs,\n", + " \"Email address\": Col.email,\n", + " \"Name\": Col.speaker_name,\n", + " \"Affiliation\": Col.affiliation,\n", + " \"Who do you know from the Committee?\": Col.committee_contact,\n", + " \"Availability during the Review Period\": Col.availability,\n", + " \"Additional comments regarding your availability during the review period.\": Col.availability_comment,\n", + " \"Activated in Pretalx\": Col.pretalx_activated,\n", + " \"Do you want your name to be listed as a reviewer on the conference website?\": Col.public,\n", + " \"Wants all proposals\": Col.all_proposals,\n", + " \"Any additional comments for the Program Committee\": Col.comment,\n", + " \"Committee Member\": Col.committee_member\n", + "}\n", + "gsheet_df.rename(columns=col_map, inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# add column to address people nicely\n", + "gsheet_df[Col.address_as] = gsheet_df[Col.speaker_name].apply(lambda x: x.split()[0].title())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "reviewers_all_df = gsheet_df[[Col.speaker_name, Col.email, Col.address_as]]\n", + "reviewers_all = reviewers_all_df.apply(lambda x: Recipient(name=x[Col.speaker_name], email=x[Col.email], address_as=x[Col.address_as]), axis=1).to_list()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# determine reviewers having not even activated the Pretalx Acccount \n", + "reviewers_not_activated_df = gsheet_df.loc[gsheet_df[Col.pretalx_activated].isna(), [Col.speaker_name, Col.email, Col.address_as]]\n", + "reviewers_not_activated = reviewers_not_activated_df.apply(lambda x: Recipient(name=x[Col.speaker_name], email=x[Col.email], address_as=x[Col.address_as]), axis=1).to_list()\n", + "\n", + "# TODO: add Committee Member as column to the Reviewers spreadsheet in the Google Drive \n", + "# NOTE: in the last years we have as well excluded Committee members, which I have not done here as I don't have the information in the Spreadsheet (and I believe sending emails to the committee members is not a problem anyways)\n", + "# & gsheet_df[Col.committee_member].isna()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: add Pretalx Email as column to the spreadsheet in the Google Drive \n", + "# for activated reviewers we take the e-mail address of their pretalx account\n", + "reviewers_activated_df = gsheet_df.loc[gsheet_df[Col.pretalx_activated].notnull()] # , [Col.speaker_name, 'Pretalx Mail', Col.address_as]\n", + "reviewers_activated = reviewers_activated_df.apply(lambda x: Recipient(name=x[Col.speaker_name], email=x['Pretalx Mail'], address_as=x[Col.address_as]), axis=1).to_list()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Initial Mail to Reviewers for Onboarding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as}!\n", + "\n", + "I hope this message finds you well. As the Chair of the Programme Committee for PyConDE & PyData,\n", + "it's my pleasure to welcome you to our team. Your contribution is vital to the success of our upcoming event.\n", + "\n", + "Today, you should have received an invitation from noreply@pretalx.com to join Pretalx, our platform for\n", + "managing conference submissions. Please follow the link in the email to activate your account and\n", + "ensure you keep your login credentials safe.\n", + "\n", + "We will be sending out more detailed information and guidelines in the new year.\n", + "In the meantime, if you encounter any issues signing up or have any questions,\n", + "feel free to reach out to us at program25@pycon.de.\n", + "\n", + "Until then, I wish you a joyful Christmas season and a fantastic start to the New Year!\n", + "\n", + "Warm regards,\n", + "\n", + "Florian Wilhelm\n", + "Program Committee Chair\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"Welcome to PyConDE & PyData 2025 Review Team - Important Account Activation Information\",\n", + " body=mail_body,\n", + " recipients=reviewers_not_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mail to Reviewers that haven't activated their account in Pretalx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as} and welcome to the PyConDE / PyData 2025 review team!\n", + "\n", + "I hope this message finds you well. As the Chair of the Programme Committee for PyConDE & PyData,\n", + "it's my pleasure to welcome you to our team. Your contribution is vital to the success of our upcoming event.\n", + "\n", + "In the last few days, you should have received an invitation from noreply@pretalx.com to join Pretalx, our platform for\n", + "managing conference submissions. Have you checked your SPAM folder yet as it seems you haven't activated your\n", + "Pretalx Account for reviewing. Please follow the link in the Pretalx email to activate your account and ensure you keep\n", + "your login credentials safe. PLEASE DO THIS NOW :-)\n", + "\n", + "We will be sending out more detailed information and guidelines in the new year.\n", + "In the meantime, if you encounter any issues signing up, can't find the Pretalx email or have any questions,\n", + "feel free to reach out to us at program25@pycon.de.\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"Important! Please activate your Pretalx Account for PyConDE & PyData 2025\",\n", + " body=mail_body,\n", + " recipients=reviewers_not_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail regarding the Review Onboarding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "the end of the year 2024 is near and we are all excited about what's to come in 2025.\n", + "The Programme Committee is doing right now the final preparations to organise the review process.\n", + "\n", + "We have just updated our Reviewer Guidelines (link below) for you to read before the actual review\n", + "process will start on Wednesday, 9th of January and the deadline is Friday, 31st of January Midnight.\n", + "To meet your fellow reviewers, have a nice chat, talk to the programme committee and ask questions\n", + "personally, we also offer two non-mandatory Get Togethers on the th & th of January (details below).\n", + "\n", + "If you have any questions, need help, don't hesitate contacting us at program25@pycon.de.\n", + "We appreciate your help very much and want to make sure that you are having a good time.\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Summary:\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* [Nonobligatory] PyCon 2025 - Reviewer's Get Together, Meet & Greet and your Questions:\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "IMPORTANT: If you haven't signed up on Pretalx yet, please search for a mail from `noreply@pretalx.com`\n", + " in your mailbox, also SPAM folder and confirm it. It's necessary for our assignment of proposals for review.\n", + "\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] Information about the Review Process in 2025\",\n", + " body=mail_body,\n", + " recipients=reviewers_all\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail regarding the Review Onboarding 2 only to activated reviewers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "we hope you had a great holiday season, after all you were nice and activated your Pretalx account,\n", + "so Santa must have been generous with you ;-) One last bit of information about the review process for\n", + "this year. More to come in 2025...\n", + "\n", + "We just assigned every reviewer initially 10 proposals so that you have a chance to familiarize yourself with\n", + "Pretalx before the Reviewer's Get Together dates (see below) to ask questions. It's *not* mandatory to participate\n", + "and the official review phase will start on January 9th in 2025. So this is just a tidbit of what's to come in 2025.\n", + "\n", + "See you next year and thank you very much {recipient.address_as} for your support!\n", + "\n", + "Summary:\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* [Nonobligatory] PyCon 2025 - Reviewer's Get Together, Meet & Greet and your Questions:\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] One more thing about the Review Process in 2025\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mail to Reviewers activated in Pretalx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail regarding the Review Onboarding" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "the end of the year 2024 is near and we are all excited about what's to come in 2025.\n", + "The Programme Committee is doing right now the final preparations to organise the review process.\n", + "\n", + "We have just updated our Reviewer Guidelines (link below) for you to read before the actual review\n", + "process will start on Wednesday, 9th of January and the deadline is Friday, 31st of January Midnight.\n", + "To meet your fellow reviewers, have a nice chat, talk to the programme committee and ask questions\n", + "personally, we also offer two non-mandatory Get Togethers on the th & th of January (details below).\n", + "\n", + "If you have any questions, need help, don't hesitate contacting us at program25@pycon.de.\n", + "We appreciate your help very much and want to make sure that you are having a good time.\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Summary:\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* [Nonobligatory] PyCon 2025 - Reviewer's Get Together, Meet & Greet and your Questions:\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "IMPORTANT: If you haven't signed up on Pretalx yet, please search for a mail from `noreply@pretalx.com`\n", + " in your mailbox, also SPAM folder and confirm it. It's necessary for our assignment of proposals for review.\n", + "\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] Information about the Review Process in 2025\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail regarding the start of the Review Phase" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "les jeux sont faits! The chips are down! and our Call for Proposals is now finally closed :-)\n", + "We are very happy to announce that we have now a total of proposals! That's even more than last year.\n", + "\n", + "So let's all begin with the review process and make this year's PyConDE & PyData Darmstadt 2025 a great success.\n", + "For this year's review process will try a new approach, simplified approach to last year's process.\n", + "We will assign each reviewer about proposals but expect everyone to review only at least proposals until\n", + "the end of January. So if you have time and want to review more proposals than , please feel free to do so.\n", + "This helps out another reviewer who couldn't complete proposals for unforeseen reasons.\n", + "If you want to know more, read the PS text of this mail.\n", + "\n", + "If you have any questions, need help, don't hesitate contacting us at program25@pycon.de.\n", + "We appreciate your help very much and want to make sure that you are having a good time.\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Summary:\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* [Nonobligatory] PyCon 2025 - Reviewer's Get Together, Meet & Greet and your Questions:\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + " - Thursday, xx. January 2025 · 5:00 bis 5:40PM CET, video call: https://meet.google.com/\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\n", + "PS: In total, we are looking like last year for 3 reviews per proposal to get a fair evaluation of each proposal.\n", + "To make sure we really have 3 reviews per proposal in the end, we will initially assign each proposal to 5 reviewers.\n", + "Whenever a proposal has 3 reviews, it will be removed from the list of proposals to review for the remaining reviewers.\n", + "This is the reason why we define a minimum number of proposals to review for each reviewer but assign more proposals.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] Our Review Phase starts TODAY\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail after 1 week or reviews" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "the first of three weeks of the reviews phase are over and % of all reviewers have already started.\n", + "We have accomplished together already one third of all necessary reviews. That's great!\n", + "\n", + "So let's keep up the good work and finish the review process by the end of January.\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Information summary:\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] First week of the Review Phase\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail after 2 week or reviews" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "the second of three weeks of the review phase are over and % of all reviewers have already started.\n", + "We have accomplished together already about two third of all necessary reviews. That's great!\n", + "\n", + "If you haven't started yet, please do so now. We are almost there! ONLY 9 DAYS LEFT.\n", + "So let's keep up the good work and finish the review process by the end of January.\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Information summary:\n", + "* Please review all assigned proposals but at least proposals :-)\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] ONLY 9 DAYS LEFT!\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail after 3 week or reviews" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pretalx_client = PretalxClient()\n", + "n_reviews, reviews = pretalx_client.reviews(cfg['event_name'])\n", + "reviews = list(reviews)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "scored_reviews_df = pd.DataFrame([{\"user\": r.user, \"score\": r.score, \"n_reviews\": r.submission} for r in reviews if r.score is not None])\n", + "scored_reviews_df = scored_reviews_df.groupby(\"user\").count()[[\"n_reviews\"]]\n", + "scored_reviews_df['top_perc'] = (1. - scored_reviews_df.rank(pct=True)[\"n_reviews\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "reviewers_activated_df = pd.merge(reviewers_activated_df, scored_reviews_df, right_on='user', left_on='Pretalx Name', how='left')\n", + "reviewers_activated_df[\"n_reviews\"].fillna(0., inplace=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_feedback(x):\n", + " if x['n_reviews'] == 0.:\n", + " return \"So far you haven't reviewed any proposals, it seems. Now it's really time to get started :-)\\nPlease let us know if you are not able to review for some reason. In this case, we must assign your proposals to others soon.\"\n", + " elif x['n_reviews'] < 20.:\n", + " return \"You have reviewed only a few proposals so far, less than 20. Please review some more proposals.\\nWe are close to the finish line.\"\n", + " else:\n", + " return f\"Thanks that you already supported us so much! We are close to the finish line.\\nIf you have time, please review some more proposals.\"\n", + "\n", + "reviewers_activated_df[\"feedback\"] = reviewers_activated_df.apply(get_feedback, axis=1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "reviewers_activated = reviewers_activated_df.apply(lambda x: Recipient(name=x[Col.speaker_name], \n", + " email=x[Col.email], \n", + " address_as=x[Col.address_as], \n", + " data={\"feedback\": x[\"feedback\"]}), axis=1).to_list()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "it's the final countdown, only 5 days left until the end of the review phase\n", + "and yet we have more than % of all necessary reviews missing :-(\n", + "{recipient.data.feedback}\n", + "\n", + "Thank you very much, {recipient.address_as}, for your support!\n", + "\n", + "Information summary:\n", + "* Please review all assigned proposals but at least 22 proposals :-)\n", + "* Review period: 9. January 2025 - 31 January, 00:00 CET\n", + "* Pretalx: https://pretalx.com/orga/event/pyconde-pydata-2025/reviews/\n", + "* Reviewer Guidelines (https://docs.google.com/document/d/1zncTc8gm7OUIIWt175YohriJ5ux7yHkLJFBpQvwNyX8/edit?tab=t.0#heading=h.hfsau13gky5q)\n", + "* Contact program25@pycon.de for support if needed\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Daarmstadt 2025\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] ONLY 5 DAYS LEFT FOR YOUR REVIEWS!\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mail End of Review!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def get_feedback(x):\n", + " if x['n_reviews'] == 0.:\n", + " return \"It seems you couldn't review and if you had problems or technical reasons please let us know :-)\"\n", + " else:\n", + " return 'Thanks that you supported us so much! We are really happy about your contribution.'\n", + "\n", + "reviewers_activated_df[\"feedback\"] = reviewers_activated_df.apply(get_feedback, axis=1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "reviewers_activated = reviewers_activated_df.apply(lambda x: Recipient(name=x[Col.speaker_name], \n", + " email=x[Col.email], \n", + " address_as=x[Col.address_as], \n", + " data={\"feedback\": x[\"feedback\"]}), axis=1).to_list()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_body = \"\"\"\n", + "Hi {recipient.address_as},\n", + "\n", + "it's done! The review phase is over and we have accomplished together a great job.\n", + "And we are finished even one day before the deadline :-)\n", + "\n", + "{recipient.data.feedback}\n", + "Together, more than reviewers wrote about reviews for roughly proposals.\n", + "That's amazing!\n", + "\n", + "All the best,\n", + "Program Committee\n", + "PyCon DE & PyData Darmstadt 2025 (program25@pycon.de)\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail = Mail(\n", + " subject=\"[PyConDE/PyData 2025] The Review Phase is Over!\",\n", + " body=mail_body,\n", + " recipients=reviewers_activated\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mail_client = MailClient()\n", + "responses, errors = mail_client.send(mail)\n", + "assert not errors" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}