mediagoblin.util.send_email now supports both list() and string() in the 'to_addrs...
[mediagoblin.git] / mediagoblin / util.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011 Free Software Foundation, Inc
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 from email.MIMEText import MIMEText
18 import smtplib
19 import sys
20
21 import jinja2
22 import mongokit
23
24
25 TESTS_ENABLED = False
26 def _activate_testing():
27 """
28 Call this to activate testing in util.py
29 """
30 global TESTS_ENABLED
31 TESTS_ENABLED = True
32
33
34 def get_jinja_env(user_template_path=None):
35 """
36 Set up the Jinja environment, possibly allowing for user
37 overridden templates.
38
39 (In the future we may have another system for providing theming;
40 for now this is good enough.)
41 """
42 if user_template_path:
43 loader = jinja2.ChoiceLoader(
44 [jinja2.FileSystemLoader(user_template_path),
45 jinja2.PackageLoader('mediagoblin', 'templates')])
46 else:
47 loader = jinja2.PackageLoader('mediagoblin', 'templates')
48
49 return jinja2.Environment(loader=loader, autoescape=True)
50
51
52 def setup_user_in_request(request):
53 """
54 Examine a request and tack on a request.user parameter if that's
55 appropriate.
56 """
57 if not request.session.has_key('user_id'):
58 request.user = None
59 return
60
61 user = None
62 user = request.app.db.User.one(
63 {'_id': mongokit.ObjectId(request.session['user_id'])})
64
65 if not user:
66 # Something's wrong... this user doesn't exist? Invalidate
67 # this session.
68 request.session.invalidate()
69
70 request.user = user
71
72
73 def import_component(import_string):
74 """
75 Import a module component defined by STRING. Probably a method,
76 class, or global variable.
77
78 Args:
79 - import_string: a string that defines what to import. Written
80 in the format of "module1.module2:component"
81 """
82 module_name, func_name = import_string.split(':', 1)
83 __import__(module_name)
84 module = sys.modules[module_name]
85 func = getattr(module, func_name)
86 return func
87
88
89 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
90 ### Special email test stuff begins HERE
91 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
93 # We have two "test inboxes" here:
94 #
95 # EMAIL_TEST_INBOX:
96 # ----------------
97 # If you're writing test views, you'll probably want to check this.
98 # It contains a list of MIMEText messages.
99 #
100 # EMAIL_TEST_MBOX_INBOX:
101 # ----------------------
102 # This collects the messages from the FakeMhost inbox. It's reslly
103 # just here for testing the send_email method itself.
104 #
105 # Anyway this contains:
106 # - from
107 # - to: a list of email recipient addresses
108 # - message: not just the body, but the whole message, including
109 # headers, etc.
110 #
111 # ***IMPORTANT!***
112 # ----------------
113 # Before running tests that call functions which send email, you should
114 # always call _clear_test_inboxes() to "wipe" the inboxes clean.
115
116 EMAIL_TEST_INBOX = []
117 EMAIL_TEST_MBOX_INBOX = []
118
119
120 class FakeMhost(object):
121 """
122 Just a fake mail host so we can capture and test messages
123 from send_email
124 """
125 def connect(self):
126 pass
127
128 def sendmail(self, from_addr, to_addrs, message):
129 EMAIL_TEST_MBOX_INBOX.append(
130 {'from': from_addr,
131 'to': to_addrs,
132 'message': message})
133
134 def _clear_test_inboxes():
135 global EMAIL_TEST_INBOX
136 global EMAIL_TEST_MBOX_INBOX
137 EMAIL_TEST_INBOX = []
138 EMAIL_TEST_MBOX_INBOX = []
139
140 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
141 ### </Special email test stuff>
142 ### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
143
144 def send_email(from_addr, to_addrs, subject, message_body):
145 """
146 Simple email sending wrapper, use this so we can capture messages
147 for unit testing purposes.
148
149 Args:
150 - from_addr: address you're sending the email from
151 - to_addrs: list of recipient email addresses
152 - subject: subject of the email
153 - message_body: email body text
154 """
155 # TODO: make a mock mhost if testing is enabled
156 if TESTS_ENABLED:
157 mhost = FakeMhost()
158 else:
159 mhost = smtplib.SMTP()
160
161 mhost.connect()
162
163 message = MIMEText(message_body.encode('utf-8'), 'plain', 'utf-8')
164 message['Subject'] = subject
165 message['From'] = from_addr
166 # The shorthand condition takes height for the possibility that the to_addrs argument can be either list() or string()
167 message['To'] = ', '.join(to_addrs) if type( to_addrs ) == list else to_addrs
168
169 if TESTS_ENABLED:
170 EMAIL_TEST_INBOX.append(message)
171
172 return mhost.sendmail(from_addr, to_addrs, message.as_string())