notify_job_offer.py 7.48 KB
Newer Older
Matthieu Boileau's avatar
Matthieu Boileau committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
"""Email confirmation to job offer author"""

import argparse
import smtplib
from email.message import EmailMessage
from email.headerregistry import Address
from string import Template
import getpass
import os
import re
import sys
import datetime
import locale
locale.setlocale(locale.LC_TIME, '')
script_path = os.path.dirname(sys.argv[0])
sys.path.append(os.path.join(script_path, '..'))
from publishconf import SITEURL
19
import html
Matthieu Boileau's avatar
Matthieu Boileau committed
20
21
22
23
24


# Email
MAILSERVER = 'mailserver.u-strasbg.fr'
SENDER_ACCOUNT = 'math-gitlab-incoming'
gouarin's avatar
gouarin committed
25
SENDER_MAIL = "calcul-contact@services.cnrs.fr"
Matthieu Boileau's avatar
Matthieu Boileau committed
26
27
28
SENDER_NAME = "Bureau du groupe Calcul"
SENDER_ACCOUNT_DISPLAY = "calcul-contact"
SENDER_DOMAIN = "math.cnrs.fr"
Matthieu Boileau's avatar
Matthieu Boileau committed
29
RECIPIENT_MAIL = "bureau.calcul@services.cnrs.fr"
Matthieu Boileau's avatar
Matthieu Boileau committed
30
31
32
33
34
35
36
37


class Message:
    """Abstract class for message"""

    subject = ""
    template = Template("")

Matthieu Boileau's avatar
Matthieu Boileau committed
38
    def __init__(self, job_id, recipient_email=None, publisher=None):
Matthieu Boileau's avatar
Matthieu Boileau committed
39
40
        self.job_id = job_id
        self.parse_job_offer_file()
Matthieu Boileau's avatar
Matthieu Boileau committed
41
        self.recipient_name = None
Matthieu Boileau's avatar
Matthieu Boileau committed
42
43
        self.recipient_email = recipient_email

Matthieu Boileau's avatar
Matthieu Boileau committed
44
45
46
        job_url = "{}/job_{}.html".format(SITEURL, self.job_id)
        self.d = {'JOB_URL': job_url}
        if publisher:
Matthieu Boileau's avatar
Matthieu Boileau committed
47
            self.d['SIGNATURE'] = "{}, pour le bureau du groupe Calcul".format(publisher.title())
Matthieu Boileau's avatar
Matthieu Boileau committed
48
        else:
Matthieu Boileau's avatar
Matthieu Boileau committed
49
            self.d['SIGNATURE'] = 'Le bureau du groupe Calcul'
Matthieu Boileau's avatar
Matthieu Boileau committed
50
51


Matthieu Boileau's avatar
Matthieu Boileau committed
52
53
54
55
56
57
    def parse_job_offer_file(self):
        filename = f"../content/job_offers/job_{self.job_id}.md"
        filepath = os.path.join(script_path, filename)

        with open(filepath) as f:
            s = f.read()
58
            m = re.search(r"^Authors: (.*)$", s, re.MULTILINE)
59
            self.author_name = html.unescape(m.group(1)).title()
60
            m = re.search(r"^Email: (.*)$", s, re.MULTILINE)
61
            self.author_email = html.unescape(m.group(1))
62
            m = re.search(r"^Job_Type: (.*)$", s, re.MULTILINE)
63
64
65
            self.job_type = html.unescape(m.group(1)).lower()
            m = re.search(r"^Job_Duration: (.*)$", s, re.MULTILINE)
            self.job_duration = html.unescape(m.group(1)).lower()
66
            m = re.search(r"^Title: (.*)$", s, re.MULTILINE)
67
            self.job_title = html.unescape(m.group(1))
68
69
70
71
72
            m = re.search(r"^Expiration_Date: (.*)$", s, re.MULTILINE)
            if m:
                self.expire_date = datetime.datetime.strptime(m.group(1), '%Y-%m-%d')
            else:
                self.expire_date = datetime.date.today() + datetime.timedelta(days=90)
Matthieu Boileau's avatar
Matthieu Boileau committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

    def get_email_body(self):
        """Virtual function"""
        pass

    def get_msg(self):
        """Get a message object for job_id"""
        body = self.get_email_body()
        msg = EmailMessage()
        msg['Subject'] = self.subject
        msg['From'] = Address(SENDER_NAME, SENDER_ACCOUNT_DISPLAY, SENDER_DOMAIN)
        msg['To'] = self.recipient_email

        print(f">>> Sending notification to {self.recipient_name} <{self.recipient_email}>")
        print(body)
        msg.set_content(body)

        return msg


class AuthorMessage(Message):
    """A class to notify job offer authors"""

    subject = "Votre annonce d'offre d'emploi a été validée"
    template = Template("""\
Bonjour,

Merci d'avoir déposé une annonce d'offre d'emploi sur le site web du groupe Calcul.
101
102
Cette annonce a été validée par le bureau du groupe Calcul et vient d'être publiée sur $JOB_URL .
Elle sera diffusée sous peu sur la liste calcul@listes.math.cnrs.fr.
Matthieu Boileau's avatar
Matthieu Boileau committed
103
104
105
106
107

Sans demande de votre part, elle restera en ligne jusqu'au $EXPIRE_DATE.

Cordialement,

Matthieu Boileau's avatar
Matthieu Boileau committed
108
$SIGNATURE
Matthieu Boileau's avatar
Matthieu Boileau committed
109
110
111
112
113
114
115
116
117
118
""")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.recipient_name = self.author_name
        if not self.recipient_email:
            self.recipient_email = self.author_email

    def get_email_body(self):
119
        """Return email body from template"""
Matthieu Boileau's avatar
Matthieu Boileau committed
120

121
        self.d['EXPIRE_DATE'] = '{d.day} {d:%B} {d.year}'.format(d=self.expire_date)
Matthieu Boileau's avatar
Matthieu Boileau committed
122
        body = self.template.substitute(self.d)
Matthieu Boileau's avatar
Matthieu Boileau committed
123
124
125
126
127
128
129
130
131
        return body


class ListMessage(Message):
    """A class to notify diffusion list"""

    template = Template("""\
Bonjour,

132
$JOB_AUTHOR vient de publier une offre de $JOB_TYPE$JOB_DURATION concernant le poste intitulé "$JOB_TITLE".
Matthieu Boileau's avatar
Matthieu Boileau committed
133

134
Vous en retrouverez tous les détails sur $JOB_URL
Matthieu Boileau's avatar
Matthieu Boileau committed
135
136
137

Cordialement,

Matthieu Boileau's avatar
Matthieu Boileau committed
138
$SIGNATURE
Matthieu Boileau's avatar
Matthieu Boileau committed
139
140
141
142
143
144
145
""")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.recipient_name = "Groupe Calcul"
        if not self.recipient_email:
Matthieu Boileau's avatar
Matthieu Boileau committed
146
            self.recipient_email = RECIPIENT_MAIL
147
148
        self.subject = "Offre de {}{}: {}".format(
            self.job_type,
149
            " de {}".format(self.job_duration) if self.job_duration else "",
150
151
            self.job_title
        )
Matthieu Boileau's avatar
Matthieu Boileau committed
152
153
154
155

    def get_email_body(self):
        """Return email body from template"""

Matthieu Boileau's avatar
Matthieu Boileau committed
156
157
158
        self.d['JOB_AUTHOR'] = self.author_name
        self.d['JOB_TYPE'] = self.job_type
        self.d['JOB_TITLE'] = self.job_title
159
        self.d['JOB_DURATION'] = " ({})".format(self.job_duration) if self.job_duration else ""
Matthieu Boileau's avatar
Matthieu Boileau committed
160

Matthieu Boileau's avatar
Matthieu Boileau committed
161
        body = self.template.substitute(self.d)
Matthieu Boileau's avatar
Matthieu Boileau committed
162
163
164
165

        return body


Matthieu Boileau's avatar
Matthieu Boileau committed
166
def send_email(commit_title=None, job_id=None, password=None, notifier=None, recipient_email=None, publisher=None):
Matthieu Boileau's avatar
Matthieu Boileau committed
167
168
169
170
171
172
    """Send notification email using smtplib"""

    if not job_id:
        m = re.match("^Merge branch 'job_(.*)' into '(.*)'$", commit_title)
        job_id = m.group(1)

Matthieu Boileau's avatar
Matthieu Boileau committed
173
    message = notifier(job_id, recipient_email, publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    msg = message.get_msg()

    if not password:
        password = getpass.getpass(f"Please type email password for {SENDER_MAIL}: ")

    # Connect to SMTP
    with smtplib.SMTP_SSL(MAILSERVER) as smtp:
        smtp.login(SENDER_ACCOUNT, password)
        smtp.sendmail(SENDER_MAIL, msg['To'], msg.as_string())


def main():
    """Read CLI to send email"""
    parser = argparse.ArgumentParser(description="Send email notification to the author of job offer")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument('--commit_title', nargs=1, metavar='commit-title',
                       help='should be "$CI_COMMIT_TITLE" in .gitlab-ci.yml')
    group.add_argument('--job_id', nargs=1, metavar='job-id',
                       help="bf41a2147c42ef38c98a2cc47b244012 for example")
    parser.add_argument('--password', nargs=1, metavar="account-password", help="password for sender email account")
    parser.add_argument('--notifier', nargs=1, metavar="notifier-type", required=True, choices=("author", "list"),
                        help="Type for notifying message")
    parser.add_argument('--recipient_email', nargs=1, metavar="recipent-email-address",
                        help="Override default (author or list address)")
Matthieu Boileau's avatar
Matthieu Boileau committed
198
199
    parser.add_argument('--publisher', nargs=1, metavar="publish-name",
                        help="Name of Groupe Calcul's member responsible for publishing the job offer.")
Matthieu Boileau's avatar
Matthieu Boileau committed
200
201
202
203
204
    args = parser.parse_args()

    password = args.password[0] if args.password else None
    notifier = {"author": AuthorMessage, "list": ListMessage}
    recipient_email = args.recipient_email[0] if args.recipient_email else None
Matthieu Boileau's avatar
Matthieu Boileau committed
205
    publisher = args.publisher[0] if args.publisher else None
Matthieu Boileau's avatar
Matthieu Boileau committed
206
207
    if args.commit_title:
        send_email(commit_title=args.commit_title[0], password=password, notifier=notifier[args.notifier[0]],
Matthieu Boileau's avatar
Matthieu Boileau committed
208
                   recipient_email=recipient_email, publisher=publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
209
210
    elif args.job_id:
        send_email(job_id=args.job_id[0], password=password, notifier=notifier[args.notifier[0]],
Matthieu Boileau's avatar
Matthieu Boileau committed
211
                   recipient_email=recipient_email, publisher=publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
212
213
214
215


if __name__ == '__main__':
    main()