Commit b96e8e7 [frontend] refactor mailing code

3 files Authored and Committed by Jakub Kadlčík 4 days ago
[frontend] refactor mailing code

The previous code was awfully hard to read and impossible to test.

    
 1 @@ -0,0 +1,89 @@
 2 + import flask
 3 + import platform
 4 + import smtplib
 5 + from email.mime.text import MIMEText
 6 + from coprs import helpers
 7 + 
 8 + 
 9 + class Message(object):
10 +     subject = None
11 +     text = None
12 + 
13 + 
14 + class PermissionRequestMessage(Message):
15 +     def __init__(self, copr, applicant, permission_dict):
16 +         """
17 +         :param models.Copr copr:
18 +         :param models.User applicant: object of a user that applies for new permissions (e.g. flask.g.user)
19 +         :param models.CoprPermission permission: permission object
20 +         :param dict permission_dict: {"old_builder": int, "old_admin": int, "new_builder": int, "new_admin": int}
21 +         """
22 +         self.subject = "[Copr] {0}: {1} is asking permissions".format(copr.name, applicant.name)
23 +         self.text = ("{0} is asking for these permissions:\n\n"
24 +                      "Builder: {1} -> {2}\n"
25 +                      "Admin: {3} -> {4}\n\n"
26 +                      "Project: {5}\n"
27 +                      "Owner: {6}".format(
28 +                          applicant.name,
29 +                          helpers.PermissionEnum(permission_dict.get("old_builder", 0)),
30 +                          helpers.PermissionEnum(permission_dict.get("new_builder")),
31 +                          helpers.PermissionEnum(permission_dict.get("old_admin", 0)),
32 +                          helpers.PermissionEnum(permission_dict.get("new_admin")),
33 +                          copr.name,
34 +                          copr.owner_name))
35 + 
36 + 
37 + class PermissionChangeMessage(Message):
38 +     def __init__(self, copr, permission_dict):
39 +         """
40 +         :param models.Copr copr:
41 +         :param dict permission_dict: {"old_builder": int, "old_admin": int, "new_builder": int, "new_admin": int}
42 +         """
43 +         self.subject = "[Copr] {0}: Your permissions have changed".format(copr.name)
44 +         self.text = (
45 +             "Your permissions have changed:\n\n"
46 +             "Builder: {0} -> {1}\n"
47 +             "Admin: {2} -> {3}\n\n"
48 +             "Project: {4}\n"
49 +             "Owner: {5}".format(
50 +                 helpers.PermissionEnum(permission_dict["old_builder"]),
51 +                 helpers.PermissionEnum(permission_dict["new_builder"]),
52 +                 helpers.PermissionEnum(permission_dict["old_admin"]),
53 +                 helpers.PermissionEnum(permission_dict["new_admin"]),
54 +                 copr.name, copr.user.name))
55 + 
56 + 
57 + class LegalFlagMessage(Message):
58 +     def __init__(self, copr, reporter, reason):
59 +         """
60 +         :param models.Copr copr:
61 +         :param models.User reporter: A person who reported the legal issue (e.g. flask.g.user)
62 +         :param str reason: What is the legal issue?
63 +         """
64 +         self.subject = "Legal flag raised on {0}".format(copr.name)
65 +         self.text = ("{0}\n"
66 +                      "Navigate to {1}\n"
67 +                      "Contact on owner is: {2} <{3}>\n"
68 +                      "Reported by {4} <{5}>".format(
69 +                         reason,
70 +                         flask.url_for("admin_ns.legal_flag", _external=True),
71 +                         copr.user.username,
72 +                         copr.user.mail,
73 +                         reporter.name,
74 +                         reporter.mail))
75 + 
76 + 
77 + def send_mail(recipient, message, sender=None):
78 +     """
79 +     :param str/list recipient: One recipient email as a string or multiple emails in a list
80 +     :param Message message:
81 +     :param str sender: Email of a sender
82 +     :return:
83 +     """
84 +     msg = MIMEText(message.text)
85 +     msg["Subject"] = message.subject
86 +     msg["From"] = sender or "root@{0}".format(platform.node())
87 +     msg["To"] = ", ".join(recipient) if type(recipient) == list else recipient
88 +     s = smtplib.SMTP("localhost")
89 +     s.sendmail("root@{0}".format(platform.node()), recipient, msg.as_string())
90 +     s.quit()
  1 @@ -36,6 +36,7 @@
  2   from coprs.logic.stat_logic import CounterStatLogic
  3   from coprs.logic.modules_logic import ModulesLogic, ModulemdGenerator, ModuleBuildFacade
  4   from coprs.rmodels import TimedStatEvents
  5 + from coprs.mail import send_mail, LegalFlagMessage, PermissionRequestMessage, PermissionChangeMessage
  6   
  7   from coprs.logic.complex_logic import ComplexLogic
  8   
  9 @@ -564,22 +565,10 @@
 10           # sending emails
 11           if flask.current_app.config.get("SEND_EMAILS", False):
 12               for mail in admin_mails:
 13 -                 msg = MIMEText(
 14 -                     "{6} is asking for these permissions:\n\n"
 15 -                     "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
 16 -                     "Project: {4}\nOwner: {5}".format(
 17 -                         helpers.PermissionEnum(old_builder),
 18 -                         helpers.PermissionEnum(new_builder),
 19 -                         helpers.PermissionEnum(old_admin),
 20 -                         helpers.PermissionEnum(new_admin),
 21 -                         copr.name, copr.user.name, flask.g.user.name))
 22 - 
 23 -                 msg["Subject"] = "[Copr] {0}: {1} is asking permissions".format(copr.name, flask.g.user.name)
 24 -                 msg["From"] = "root@{0}".format(platform.node())
 25 -                 msg["To"] = mail
 26 -                 s = smtplib.SMTP("localhost")
 27 -                 s.sendmail("root@{0}".format(platform.node()), mail, msg.as_string())
 28 -                 s.quit()
 29 +                 permission_dict = {"old_builder": old_builder, "old_admin": old_admin,
 30 +                                    "new_builder": new_builder, "new_admin": new_admin}
 31 +                 msg = PermissionRequestMessage(copr, flask.g.user, permission_dict)
 32 +                 send_mail(mail, msg, )
 33   
 34       return flask.redirect(flask.url_for("coprs_ns.copr_detail",
 35                                           username=copr.user.name,
 36 @@ -612,23 +601,10 @@
 37                       flask.g.user, copr, perm, new_builder, new_admin)
 38                   if flask.current_app.config.get("SEND_EMAILS", False) and \
 39                           (old_builder is not new_builder or old_admin is not new_admin):
 40 - 
 41 -                     msg = MIMEText(
 42 -                         "Your permissions have changed:\n\n"
 43 -                         "Builder: {0} -> {1}\nAdmin: {2} -> {3}\n\n"
 44 -                         "Project: {4}\nOwner: {5}".format(
 45 -                             helpers.PermissionEnum(old_builder),
 46 -                             helpers.PermissionEnum(new_builder),
 47 -                             helpers.PermissionEnum(old_admin),
 48 -                             helpers.PermissionEnum(new_admin),
 49 -                             copr.name, copr.user.name))
 50 - 
 51 -                     msg["Subject"] = "[Copr] {0}: Your permissions have changed".format(copr.name)
 52 -                     msg["From"] = "root@{0}".format(platform.node())
 53 -                     msg["To"] = perm.user.mail
 54 -                     s = smtplib.SMTP("localhost")
 55 -                     s.sendmail("root@{0}".format(platform.node()), perm.user.mail, msg.as_string())
 56 -                     s.quit()
 57 +                     permission_dict = {"old_builder": old_builder, "old_admin": old_admin,
 58 +                                        "new_builder": new_builder, "new_admin": new_admin}
 59 +                     msg = PermissionChangeMessage(copr, permission_dict)
 60 +                     send_mail(perm.user.mail, msg)
 61           # for now, we don't check for actions here, as permissions operation
 62           # don't collide with any actions
 63           except exceptions.InsufficientRightsException as e:
 64 @@ -695,11 +671,10 @@
 65   @login_required
 66   @req_with_copr
 67   def copr_legal_flag(copr):
 68 -     contact_info = "{} <>".format(copr.user.username, copr.user.mail)
 69 -     return process_legal_flag(contact_info, copr)
 70 +     return process_legal_flag(copr)
 71   
 72   
 73 - def process_legal_flag(contact_info, copr):
 74 + def process_legal_flag(copr):
 75       form = forms.CoprLegalFlagForm()
 76       legal_flag = models.LegalFlag(raise_message=form.comment.data,
 77                                     raised_on=int(time.time()),
 78 @@ -707,25 +682,11 @@
 79                                     reporter=flask.g.user)
 80       db.session.add(legal_flag)
 81       db.session.commit()
 82 + 
 83       send_to = app.config["SEND_LEGAL_TO"] or ["root@localhost"]
 84 -     hostname = platform.node()
 85 -     navigate_to = "\nNavigate to http://{0}{1}".format(
 86 -         hostname, flask.url_for("admin_ns.legal_flag"))
 87 -     contact = "\nContact on owner is: {}".format(contact_info)
 88 -     reported_by = "\nReported by {0} <{1}>".format(flask.g.user.name,
 89 -                                                    flask.g.user.mail)
 90 -     try:
 91 -         msg = MIMEText(
 92 -             form.comment.data + navigate_to + contact + reported_by, "plain")
 93 -     except UnicodeEncodeError:
 94 -         msg = MIMEText(form.comment.data.encode(
 95 -             "utf-8") + navigate_to + contact + reported_by, "plain", "utf-8")
 96 -     msg["Subject"] = "Legal flag raised on {0}".format(copr.name)
 97 -     msg["From"] = "root@{0}".format(hostname)
 98 -     msg["To"] = ", ".join(send_to)
 99 -     s = smtplib.SMTP("localhost")
100 -     s.sendmail("root@{0}".format(hostname), send_to, msg.as_string())
101 -     s.quit()
102 +     msg = LegalFlagMessage(copr, flask.g.user, form.comment.data)
103 +     send_mail(send_to, msg)
104 + 
105       flask.flash("Admin has been noticed about your report"
106                   " and will investigate the project shortly.")
107       return flask.redirect(url_for_copr_details(copr))
 1 @@ -0,0 +1,33 @@
 2 + from coprs.mail import PermissionRequestMessage, PermissionChangeMessage, LegalFlagMessage
 3 + from tests.coprs_test_case import CoprsTestCase
 4 + from coprs import app
 5 + 
 6 + 
 7 + class TestMail(CoprsTestCase):
 8 +     def test_permissions_request_message(self, f_users, f_coprs, f_copr_permissions, f_db):
 9 +         msg = PermissionRequestMessage(self.c1, self.u2, {"new_builder": 1, "new_admin": 0})
10 +         assert msg.subject == "[Copr] foocopr: user2 is asking permissions"
11 +         assert msg.text == ("user2 is asking for these permissions:\n\n"
12 +                             "Builder: nothing -> request\n"
13 +                             "Admin: nothing -> nothing\n\n"
14 +                             "Project: foocopr\n"
15 +                             "Owner: user1")
16 + 
17 +     def test_permissions_change_message(self, f_users, f_coprs, f_copr_permissions, f_db):
18 +         msg = PermissionChangeMessage(self.c1, {"old_builder": 0, "old_admin": 2, "new_builder": 2, "new_admin": 0})
19 +         assert msg.subject == "[Copr] foocopr: Your permissions have changed"
20 +         assert msg.text == ("Your permissions have changed:\n\n"
21 +                             "Builder: nothing -> approved\n"
22 +                             "Admin: approved -> nothing\n\n"
23 +                             "Project: foocopr\n"
24 +                             "Owner: user1")
25 + 
26 +     def test_legal_flag_message(self, f_users, f_coprs, f_db):
27 +         app.config["SERVER_NAME"] = "localhost"
28 +         with app.app_context():
29 +             msg = LegalFlagMessage(self.c1, self.u2, "There are forbidden packages in the project")
30 +             assert msg.subject == "Legal flag raised on foocopr"
31 +             assert msg.text == ("There are forbidden packages in the project\n"
32 +                                 "Navigate to http://localhost/admin/legal-flag/\n"
33 +                                 "Contact on owner is: user1 <user1@foo.bar>\n"
34 +                                 "Reported by user2 <user2@spam.foo>")