notify_job_offer.py 7.04 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
19
20
21
22
23
24
25
26
27
#!/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


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


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

    subject = ""
    template = Template("")

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

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


Matthieu Boileau's avatar
Matthieu Boileau committed
51
52
53
54
55
56
    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()
57
            m = re.search(r"^Authors: (.*)$", s, re.MULTILINE)
Matthieu Boileau's avatar
Matthieu Boileau committed
58
            self.author_name = m.group(1).title()
59
            m = re.search(r"^Email: (.*)$", s, re.MULTILINE)
Matthieu Boileau's avatar
Matthieu Boileau committed
60
            self.author_email = m.group(1)
61
            m = re.search(r"^Job_Type: (.*)$", s, re.MULTILINE)
Matthieu Boileau's avatar
Matthieu Boileau committed
62
            self.job_type = m.group(1).lower()
63
            m = re.search(r"^Title: (.*)$", s, re.MULTILINE)
Matthieu Boileau's avatar
Matthieu Boileau committed
64
            self.job_title = m.group(1)
65
66
67
68
69
            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
70
71
72
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
101
102
103
104
105

    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.
Cette annonce a été validée par le bureau du groupe Calcul et vient d'être :
  - publiée sur $JOB_URL
  - diffusée sur la liste calcul@listes.math.cnrs.fr.

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

Cordialement,

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

    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):
117
        """Return email body from template"""
Matthieu Boileau's avatar
Matthieu Boileau committed
118

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


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

    template = Template("""\
Bonjour,

$JOB_AUTHOR vient de publier une offre de $JOB_TYPE concernant le poste intitulé "$JOB_TITLE".

Vous en retrouverez tous les détails sur $JOB_URL.

Cordialement,

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

    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
144
            self.recipient_email = RECIPIENT_MAIL
Matthieu Boileau's avatar
Matthieu Boileau committed
145
146
147
148
149
        self.subject = "Proposition de {}".format(self.job_type)

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

Matthieu Boileau's avatar
Matthieu Boileau committed
150
151
152
        self.d['JOB_AUTHOR'] = self.author_name
        self.d['JOB_TYPE'] = self.job_type
        self.d['JOB_TITLE'] = self.job_title
Matthieu Boileau's avatar
Matthieu Boileau committed
153

Matthieu Boileau's avatar
Matthieu Boileau committed
154
        body = self.template.substitute(self.d)
Matthieu Boileau's avatar
Matthieu Boileau committed
155
156
157
158

        return body


Matthieu Boileau's avatar
Matthieu Boileau committed
159
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
160
161
162
163
164
165
    """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
166
    message = notifier(job_id, recipient_email, publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    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
191
192
    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
193
194
195
196
197
    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
198
    publisher = args.publisher[0] if args.publisher else None
Matthieu Boileau's avatar
Matthieu Boileau committed
199
200
    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
201
                   recipient_email=recipient_email, publisher=publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
202
203
    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
204
                   recipient_email=recipient_email, publisher=publisher)
Matthieu Boileau's avatar
Matthieu Boileau committed
205
206
207
208


if __name__ == '__main__':
    main()