Merge lp:~therp-nl/server-env-tools/6.1-fetchmail_attach_from_folder into lp:~server-env-tools-core-editors/server-env-tools/6.1
- 6.1-fetchmail_attach_from_folder
- Merge into 6.1
Status: | Merged |
---|---|
Merged at revision: | 35 |
Proposed branch: | lp:~therp-nl/server-env-tools/6.1-fetchmail_attach_from_folder |
Merge into: | lp:~server-env-tools-core-editors/server-env-tools/6.1 |
Diff against target: |
1012 lines (+938/-0) 14 files modified
fetchmail_attach_from_folder/__init__.py (+25/-0) fetchmail_attach_from_folder/__openerp__.py (+45/-0) fetchmail_attach_from_folder/match_algorithm/__init__.py (+26/-0) fetchmail_attach_from_folder/match_algorithm/base.py (+43/-0) fetchmail_attach_from_folder/match_algorithm/email_domain.py (+44/-0) fetchmail_attach_from_folder/match_algorithm/email_exact.py (+56/-0) fetchmail_attach_from_folder/match_algorithm/openerp_standard.py (+51/-0) fetchmail_attach_from_folder/model/__init__.py (+24/-0) fetchmail_attach_from_folder/model/fetchmail_server.py (+287/-0) fetchmail_attach_from_folder/model/fetchmail_server_folder.py (+120/-0) fetchmail_attach_from_folder/view/fetchmail_server.xml (+58/-0) fetchmail_attach_from_folder/wizard/__init__.py (+23/-0) fetchmail_attach_from_folder/wizard/attach_mail_manually.py (+110/-0) fetchmail_attach_from_folder/wizard/attach_mail_manually.xml (+26/-0) |
To merge this branch: | bzr merge lp:~therp-nl/server-env-tools/6.1-fetchmail_attach_from_folder |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Fayolle - camptocamp | code review, no test | Approve | |
Ronald Portier (Therp) (community) | Approve | ||
Stefan Rijnhart (Opener) | Pending | ||
Review via email: mp+159651@code.launchpad.net |
This proposal supersedes a proposal from 2013-04-05.
Commit message
Description of the change
Found a concurrency problem, causing long running fetching threads to be called multiple times, resulting in duplicated mails
Stefan Rijnhart (Opener) (stefan-opener) wrote : Posted in a previous version of this proposal | # |
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : Posted in a previous version of this proposal | # |
Suggested enhancements:
formatting : would have been nice to get the proper spaces added (after commas, before and after assignment equal signs...)
the fetch_mail method (line 416 of the MP) could be split. I would personnally add one method for the body of the "for folder" loop and another for the body of the for message loop. This gains 8 columns, with allows for less line wrapping and clearer code, within the 80 col convention.
line 497: prefer "key in dictionary" to dictionary.
line 632: you are passing a cmp func to sorted to compare by the first element of a tuple. There are several small issues in there:
1. it is more efficient to use the key named argument (passing itemgetter(0) as key function in this case)
2. but it looks to me that the default sorting of Python does exactly what you want
3. you have a local list : using tuple(sorted(
in the column definitions (line 634 of the MP and following), using double quotes as delimiter removes the need to escape the single quotes inside the various strings, which makes the code easier to read.
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal | # |
Hello Holger,
I made a slightly modified branch:
https:/
- solved a problem when trying to match on either, from, or to, or cc, or bcc: code was chocking on fields not present in mail.
- enhanced change of matching by converting address to lowercase. To complement this, really should be a good idea to have only lower case e-mail adresses in for instance res.partner.address as well. Or have a view that always converts to lowercase...
- some minor code reorganisations to make it easer to step debug and see what is going on.
Ronald
Holger Brunn (Therp) (hbrunn) wrote : Posted in a previous version of this proposal | # |
Thanks Ronald, would you issue a merge request on this branch as a reminder? I see that assumingly your IDE already took care of a few formatting issues that were pointed out by Alexandre, but there's more to do for me
Stefan Rijnhart (Opener) (stefan-opener) wrote : Posted in a previous version of this proposal | # |
Thanks everyone, great to see such collaboration!
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal | # |
Holger,
I just noticed that any mail retrieved gets a status 'received'.
However, it is possible to retrieve both received and send-mail.
So if the customer-email address is found in a sender field (most likely from), the mail is really received.
If it found in a receiver field (to, cc or bcc), the mail should get a status sent.
Kind regard, Ronald
Holger Brunn (Therp) (hbrunn) wrote : Posted in a previous version of this proposal | # |
Ronald: That's a very good point, thanks. But I think it depends too much on the configured object/field what the state of a message should be to put it into the code. That's why I made it a configuration option for a folder in rev30, with 'received' as default.
Alexandre: Today I did the refactoring you proposed, now I think all your points are covered. Could you have another look?
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : Posted in a previous version of this proposal | # |
LGTM.
Thanks for taking the time to implement my suggestions.
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal | # |
Holger,
Great improvements! Thanx.
Sorry to bother you, but I have one more concern: when we are searching for matches, I think there will be a danger that we match on our own e-mail, instead of the partner e-mail.
Example, suppose I have a folder for all my customer mail. Matching will be done on email in res.partner.
As I have ingoing and outgoing mail in the same folder, I create two configurations/
Now when I send a mail to a customer, it will find my own e-mail in from, an ingoing mail will be registered, with myself as the customer.
So I think there should be a way to exclude our own e-mail addresses from the search. Maybe by having all mail addresses with our own domain (might be multiple!) excluded from the search results.
What do you think?
Regards, Ronald
Holger Brunn (Therp) (hbrunn) wrote : Posted in a previous version of this proposal | # |
I think you can exclude such cases by setting a domain in your configuration. So for matching customers only, you could use [('is_customer'
In the end you get an expression like
((model_
Does this help?
Holger Brunn (Therp) (hbrunn) wrote : Posted in a previous version of this proposal | # |
now I realize btw that today's refactoring would be a lot more useful if the functions passed down the ids of the mail.message(s) created. I'll fix that tomorrow
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal | # |
Approve.
I tested the following use-case: single imap folder contains mail sent to and received from customers.
Did the following configuration;
- Created an incoming server document, with all the usual options
- Linked two folder configurations to this document:
1. - Folder 'Klanten' (customers)
- match algorithm: Exact mailaddress
- Model 'relatieadressen' (res.partner.
- Field (emal): from
- Field (model): email
- Message state: Received
- Domain: [('partner_
- Delete matches: False
- Flag nonmatching: True
- Use first match: True
2. The same as 1., except for the following:
- Field (email): to, cc, bcc
- Message state: Sent
I then used my mail client to send a mail wit an attachment (here our offer....) to a test customer-email. Then I used the test customer email account to sent back a reply, (I agree to the offer, find enclosed...), with another attachment.
Then I placed both the e-mail sent, and the reply received in the folder Klanten (customers) and ran the receive mail action in the incoming mail server document.
Outcome was as expected:
- I could find both mails, with the right status, on the tab 'Email' within the partner record
- I could see and open both the outgoing and the incoming attachment from within OpenERP.
Kind regards,
Ronald
Ronald Portier (Therp) (rportier1962) wrote : | # |
Saw the problem. Solution looks good to me.
- 34. By Ronald Portier (Therp)
-
[MRG] [ADD] mail_client_view: gives normal users access to the mail views.
The only other possibilities users have of looking at e-mails, is through the
partner object, or other objects mails are directly linked to. This makes it
impossible to get an overall view, or to search through mails.Furthermore the module makes newly received mails stand out with a red circle
in the mail view. These mails are in need of action. Via a simple click a user
can either mark a message as also in need of action, or the other way around,
as having been handled.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) : | # |
- 35. By Holger Brunn (Therp)
-
[MRG][ADD] fetchmail_
attach_ from_folder Adds the possibility to attach emails from a certain IMAP folder to objects,
ie partners. Matching is done via several algorithms, ie email address.This gives a simple possibility to archive emails in OpenERP without a mail
client integration.
Preview Diff
1 | === added directory 'fetchmail_attach_from_folder' |
2 | === added file 'fetchmail_attach_from_folder/__init__.py' |
3 | --- fetchmail_attach_from_folder/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ fetchmail_attach_from_folder/__init__.py 2013-04-18 14:54:31 +0000 |
5 | @@ -0,0 +1,25 @@ |
6 | +# -*- encoding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
11 | +# All Rights Reserved |
12 | +# |
13 | +# This program is free software: you can redistribute it and/or modify |
14 | +# it under the terms of the GNU Affero General Public License as |
15 | +# published by the Free Software Foundation, either version 3 of the |
16 | +# License, or (at your option) any later version. |
17 | +# |
18 | +# This program is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU Affero General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU Affero General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | +# |
26 | +############################################################################## |
27 | + |
28 | +import match_algorithm |
29 | +import model |
30 | +import wizard |
31 | |
32 | === added file 'fetchmail_attach_from_folder/__openerp__.py' |
33 | --- fetchmail_attach_from_folder/__openerp__.py 1970-01-01 00:00:00 +0000 |
34 | +++ fetchmail_attach_from_folder/__openerp__.py 2013-04-18 14:54:31 +0000 |
35 | @@ -0,0 +1,45 @@ |
36 | +# -*- encoding: utf-8 -*- |
37 | +############################################################################## |
38 | +# |
39 | +# OpenERP, Open Source Management Solution |
40 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
41 | +# All Rights Reserved |
42 | +# |
43 | +# This program is free software: you can redistribute it and/or modify |
44 | +# it under the terms of the GNU Affero General Public License as |
45 | +# published by the Free Software Foundation, either version 3 of the |
46 | +# License, or (at your option) any later version. |
47 | +# |
48 | +# This program is distributed in the hope that it will be useful, |
49 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
50 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
51 | +# GNU Affero General Public License for more details. |
52 | +# |
53 | +# You should have received a copy of the GNU Affero General Public License |
54 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
55 | +# |
56 | +############################################################################## |
57 | + |
58 | +{ |
59 | + 'name': 'Attach mails in an IMAP folder to existing objects', |
60 | + 'version': '1.0', |
61 | + 'description': """ |
62 | + Adds the possibility to attach emails from a certain IMAP folder to objects, |
63 | + ie partners. Matching is done via several algorithms, ie email address. |
64 | + |
65 | + This gives a simple possibility to archive emails in OpenERP without a mail |
66 | + client integration. |
67 | + """, |
68 | + 'author': 'Therp BV', |
69 | + 'website': 'http://www.therp.nl', |
70 | + "category": "Tools", |
71 | + "depends": ['fetchmail'], |
72 | + 'data': [ |
73 | + 'view/fetchmail_server.xml', |
74 | + 'wizard/attach_mail_manually.xml', |
75 | + ], |
76 | + 'js': [], |
77 | + 'installable': True, |
78 | + 'active': False, |
79 | + 'certificate': '', |
80 | +} |
81 | |
82 | === added directory 'fetchmail_attach_from_folder/match_algorithm' |
83 | === added file 'fetchmail_attach_from_folder/match_algorithm/__init__.py' |
84 | --- fetchmail_attach_from_folder/match_algorithm/__init__.py 1970-01-01 00:00:00 +0000 |
85 | +++ fetchmail_attach_from_folder/match_algorithm/__init__.py 2013-04-18 14:54:31 +0000 |
86 | @@ -0,0 +1,26 @@ |
87 | +# -*- encoding: utf-8 -*- |
88 | +############################################################################## |
89 | +# |
90 | +# OpenERP, Open Source Management Solution |
91 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
92 | +# All Rights Reserved |
93 | +# |
94 | +# This program is free software: you can redistribute it and/or modify |
95 | +# it under the terms of the GNU Affero General Public License as |
96 | +# published by the Free Software Foundation, either version 3 of the |
97 | +# License, or (at your option) any later version. |
98 | +# |
99 | +# This program is distributed in the hope that it will be useful, |
100 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
101 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
102 | +# GNU Affero General Public License for more details. |
103 | +# |
104 | +# You should have received a copy of the GNU Affero General Public License |
105 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
106 | +# |
107 | +############################################################################## |
108 | + |
109 | +import base |
110 | +import email_exact |
111 | +import email_domain |
112 | +import openerp_standard |
113 | |
114 | === added file 'fetchmail_attach_from_folder/match_algorithm/base.py' |
115 | --- fetchmail_attach_from_folder/match_algorithm/base.py 1970-01-01 00:00:00 +0000 |
116 | +++ fetchmail_attach_from_folder/match_algorithm/base.py 2013-04-18 14:54:31 +0000 |
117 | @@ -0,0 +1,43 @@ |
118 | +# -*- encoding: utf-8 -*- |
119 | +############################################################################## |
120 | +# |
121 | +# OpenERP, Open Source Management Solution |
122 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
123 | +# All Rights Reserved |
124 | +# |
125 | +# This program is free software: you can redistribute it and/or modify |
126 | +# it under the terms of the GNU Affero General Public License as |
127 | +# published by the Free Software Foundation, either version 3 of the |
128 | +# License, or (at your option) any later version. |
129 | +# |
130 | +# This program is distributed in the hope that it will be useful, |
131 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
132 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
133 | +# GNU Affero General Public License for more details. |
134 | +# |
135 | +# You should have received a copy of the GNU Affero General Public License |
136 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
137 | +# |
138 | +############################################################################## |
139 | + |
140 | +class base(object): |
141 | + name = None |
142 | + '''Name shown to the user''' |
143 | + |
144 | + required_fields = [] |
145 | + '''Fields on fetchmail_server folder that are required for this algorithm''' |
146 | + |
147 | + readonly_fields = [] |
148 | + '''Fields on fetchmail_server folder that are readonly for this algorithm''' |
149 | + |
150 | + |
151 | + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
152 | + '''Returns ids found for model with mail_message''' |
153 | + return [] |
154 | + |
155 | + def handle_match( |
156 | + self, cr, uid, connection, object_id, folder, |
157 | + mail_message, mail_message_org, msgid, context=None): |
158 | + '''Do whatever it takes to handle a match''' |
159 | + return folder.server_id.attach_mail(connection, object_id, folder, |
160 | + mail_message, msgid) |
161 | |
162 | === added file 'fetchmail_attach_from_folder/match_algorithm/email_domain.py' |
163 | --- fetchmail_attach_from_folder/match_algorithm/email_domain.py 1970-01-01 00:00:00 +0000 |
164 | +++ fetchmail_attach_from_folder/match_algorithm/email_domain.py 2013-04-18 14:54:31 +0000 |
165 | @@ -0,0 +1,44 @@ |
166 | +# -*- encoding: utf-8 -*- |
167 | +############################################################################## |
168 | +# |
169 | +# OpenERP, Open Source Management Solution |
170 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
171 | +# All Rights Reserved |
172 | +# |
173 | +# This program is free software: you can redistribute it and/or modify |
174 | +# it under the terms of the GNU Affero General Public License as |
175 | +# published by the Free Software Foundation, either version 3 of the |
176 | +# License, or (at your option) any later version. |
177 | +# |
178 | +# This program is distributed in the hope that it will be useful, |
179 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
180 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
181 | +# GNU Affero General Public License for more details. |
182 | +# |
183 | +# You should have received a copy of the GNU Affero General Public License |
184 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
185 | +# |
186 | +############################################################################## |
187 | + |
188 | +from email_exact import email_exact |
189 | + |
190 | +class email_domain(email_exact): |
191 | + '''Search objects by domain name of email address. |
192 | + Beware of match_first here, this is most likely to get it wrong (gmail)''' |
193 | + name = 'Domain of email address' |
194 | + |
195 | + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
196 | + ids = super(email_domain, self).search_matches( |
197 | + cr, uid, conf, mail_message, mail_message_org) |
198 | + if not ids: |
199 | + domains = [] |
200 | + for addr in self._get_mailaddresses(conf, mail_message): |
201 | + domains.append(addr.split('@')[-1]) |
202 | + ids = conf.pool.get(conf.model_id.model).search( |
203 | + cr, uid, |
204 | + self._get_mailaddress_search_domain( |
205 | + conf, mail_message, |
206 | + operator='like', |
207 | + values=['%@'+domain for domain in set(domains)]), |
208 | + order=conf.model_order) |
209 | + return ids |
210 | |
211 | === added file 'fetchmail_attach_from_folder/match_algorithm/email_exact.py' |
212 | --- fetchmail_attach_from_folder/match_algorithm/email_exact.py 1970-01-01 00:00:00 +0000 |
213 | +++ fetchmail_attach_from_folder/match_algorithm/email_exact.py 2013-04-18 14:54:31 +0000 |
214 | @@ -0,0 +1,56 @@ |
215 | +# -*- encoding: utf-8 -*- |
216 | +############################################################################## |
217 | +# |
218 | +# OpenERP, Open Source Management Solution |
219 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
220 | +# All Rights Reserved |
221 | +# |
222 | +# This program is free software: you can redistribute it and/or modify |
223 | +# it under the terms of the GNU Affero General Public License as |
224 | +# published by the Free Software Foundation, either version 3 of the |
225 | +# License, or (at your option) any later version. |
226 | +# |
227 | +# This program is distributed in the hope that it will be useful, |
228 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
229 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
230 | +# GNU Affero General Public License for more details. |
231 | +# |
232 | +# You should have received a copy of the GNU Affero General Public License |
233 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
234 | +# |
235 | +############################################################################## |
236 | + |
237 | +from base import base |
238 | +from openerp.tools.safe_eval import safe_eval |
239 | +from openerp.addons.mail.mail_message import to_email |
240 | + |
241 | +class email_exact(base): |
242 | + '''Search for exactly the mailadress as noted in the email''' |
243 | + |
244 | + name = 'Exact mailadress' |
245 | + required_fields = ['model_field', 'mail_field'] |
246 | + |
247 | + def _get_mailaddresses(self, conf, mail_message): |
248 | + mailaddresses = [] |
249 | + fields = conf.mail_field.split(',') |
250 | + for field in fields: |
251 | + if field in mail_message: |
252 | + mailaddresses += to_email(mail_message[field]) |
253 | + return [ addr.lower() for addr in mailaddresses ] |
254 | + |
255 | + def _get_mailaddress_search_domain( |
256 | + self, conf, mail_message, operator='=', values=None): |
257 | + mailaddresses = values or self._get_mailaddresses( |
258 | + conf, mail_message) |
259 | + if not mailaddresses: |
260 | + return [(0, '=', 1)] |
261 | + search_domain = ((['|'] * (len(mailaddresses) - 1)) + [ |
262 | + (conf.model_field, operator, addr) for addr in mailaddresses] + |
263 | + safe_eval(conf.domain or '[]')) |
264 | + return search_domain |
265 | + |
266 | + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
267 | + conf_model = conf.pool.get(conf.model_id.model) |
268 | + search_domain = self._get_mailaddress_search_domain(conf, mail_message) |
269 | + return conf_model.search( |
270 | + cr, uid, search_domain, order=conf.model_order) |
271 | |
272 | === added file 'fetchmail_attach_from_folder/match_algorithm/openerp_standard.py' |
273 | --- fetchmail_attach_from_folder/match_algorithm/openerp_standard.py 1970-01-01 00:00:00 +0000 |
274 | +++ fetchmail_attach_from_folder/match_algorithm/openerp_standard.py 2013-04-18 14:54:31 +0000 |
275 | @@ -0,0 +1,51 @@ |
276 | +# -*- encoding: utf-8 -*- |
277 | +############################################################################## |
278 | +# |
279 | +# OpenERP, Open Source Management Solution |
280 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
281 | +# All Rights Reserved |
282 | +# |
283 | +# This program is free software: you can redistribute it and/or modify |
284 | +# it under the terms of the GNU Affero General Public License as |
285 | +# published by the Free Software Foundation, either version 3 of the |
286 | +# License, or (at your option) any later version. |
287 | +# |
288 | +# This program is distributed in the hope that it will be useful, |
289 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
290 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
291 | +# GNU Affero General Public License for more details. |
292 | +# |
293 | +# You should have received a copy of the GNU Affero General Public License |
294 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
295 | +# |
296 | +############################################################################## |
297 | + |
298 | +from base import base |
299 | +from openerp.tools.safe_eval import safe_eval |
300 | + |
301 | +class openerp_standard(base): |
302 | + '''No search at all. Use OpenERP's standard mechanism to attach mails to |
303 | + mail.thread objects. Note that this algorithm always matches.''' |
304 | + |
305 | + name = 'OpenERP standard' |
306 | + readonly_fields = ['model_field', 'mail_field', 'match_first', 'domain', |
307 | + 'model_order', 'flag_nonmatching'] |
308 | + |
309 | + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): |
310 | + '''Always match. Duplicates will be fished out by message_id''' |
311 | + return [True] |
312 | + |
313 | + def handle_match( |
314 | + self, cr, uid, connection, object_id, folder, |
315 | + mail_message, mail_message_org, msgid, context): |
316 | + result = folder.pool.get('mail.thread').message_process( |
317 | + cr, uid, |
318 | + folder.model_id.model, mail_message_org, |
319 | + save_original=folder.server_id.original, |
320 | + strip_attachments=(not folder.server_id.attach), |
321 | + context=context) |
322 | + |
323 | + if folder.delete_matching: |
324 | + connection.store(msgid, '+FLAGS', '\\DELETED') |
325 | + |
326 | + return [result] |
327 | |
328 | === added directory 'fetchmail_attach_from_folder/model' |
329 | === added file 'fetchmail_attach_from_folder/model/__init__.py' |
330 | --- fetchmail_attach_from_folder/model/__init__.py 1970-01-01 00:00:00 +0000 |
331 | +++ fetchmail_attach_from_folder/model/__init__.py 2013-04-18 14:54:31 +0000 |
332 | @@ -0,0 +1,24 @@ |
333 | +# -*- encoding: utf-8 -*- |
334 | +############################################################################## |
335 | +# |
336 | +# OpenERP, Open Source Management Solution |
337 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
338 | +# All Rights Reserved |
339 | +# |
340 | +# This program is free software: you can redistribute it and/or modify |
341 | +# it under the terms of the GNU Affero General Public License as |
342 | +# published by the Free Software Foundation, either version 3 of the |
343 | +# License, or (at your option) any later version. |
344 | +# |
345 | +# This program is distributed in the hope that it will be useful, |
346 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
347 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
348 | +# GNU Affero General Public License for more details. |
349 | +# |
350 | +# You should have received a copy of the GNU Affero General Public License |
351 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
352 | +# |
353 | +############################################################################## |
354 | + |
355 | +import fetchmail_server |
356 | +import fetchmail_server_folder |
357 | |
358 | === added file 'fetchmail_attach_from_folder/model/fetchmail_server.py' |
359 | --- fetchmail_attach_from_folder/model/fetchmail_server.py 1970-01-01 00:00:00 +0000 |
360 | +++ fetchmail_attach_from_folder/model/fetchmail_server.py 2013-04-18 14:54:31 +0000 |
361 | @@ -0,0 +1,287 @@ |
362 | +# -*- encoding: utf-8 -*- |
363 | +############################################################################## |
364 | +# |
365 | +# OpenERP, Open Source Management Solution |
366 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
367 | +# All Rights Reserved |
368 | +# |
369 | +# This program is free software: you can redistribute it and/or modify |
370 | +# it under the terms of the GNU Affero General Public License as |
371 | +# published by the Free Software Foundation, either version 3 of the |
372 | +# License, or (at your option) any later version. |
373 | +# |
374 | +# This program is distributed in the hope that it will be useful, |
375 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
376 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
377 | +# GNU Affero General Public License for more details. |
378 | +# |
379 | +# You should have received a copy of the GNU Affero General Public License |
380 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
381 | +# |
382 | +############################################################################## |
383 | + |
384 | +import base64 |
385 | +import simplejson |
386 | +from lxml import etree |
387 | +from openerp.osv.orm import Model, except_orm, browse_null |
388 | +from openerp.tools.translate import _ |
389 | +from openerp.osv import fields |
390 | +from openerp.addons.fetchmail.fetchmail import logger |
391 | +from openerp.tools.misc import UnquoteEvalContext |
392 | +from openerp.tools.safe_eval import safe_eval |
393 | + |
394 | + |
395 | +class fetchmail_server(Model): |
396 | + _inherit = 'fetchmail.server' |
397 | + |
398 | + _columns = { |
399 | + 'folder_ids': fields.one2many( |
400 | + 'fetchmail.server.folder', 'server_id', 'Folders'), |
401 | + } |
402 | + |
403 | + _defaults = { |
404 | + 'type': 'imap', |
405 | + } |
406 | + |
407 | + def __init__(self, pool, cr): |
408 | + self._columns['object_id'].required = False |
409 | + return super(fetchmail_server, self).__init__(pool, cr) |
410 | + |
411 | + def onchange_server_type( |
412 | + self, cr, uid, ids, server_type=False, ssl=False, |
413 | + object_id=False): |
414 | + retval = super( |
415 | + fetchmail_server, self).onchange_server_type(cr, uid, |
416 | + ids, server_type, ssl, |
417 | + object_id) |
418 | + retval['value']['state'] = 'draft' |
419 | + return retval |
420 | + |
421 | + def fetch_mail(self, cr, uid, ids, context=None): |
422 | + if context is None: |
423 | + context = {} |
424 | + |
425 | + check_original = [] |
426 | + |
427 | + for this in self.browse(cr, uid, ids, context): |
428 | + if this.object_id: |
429 | + check_original.append(this.id) |
430 | + |
431 | + context.update( |
432 | + { |
433 | + 'fetchmail_server_id': this.id, |
434 | + 'server_type': this.type |
435 | + }) |
436 | + |
437 | + connection = this.connect() |
438 | + for folder in this.folder_ids: |
439 | + this.handle_folder(connection, folder) |
440 | + |
441 | + connection.close() |
442 | + |
443 | + return super(fetchmail_server, self).fetch_mail( |
444 | + cr, uid, check_original, context) |
445 | + |
446 | + def handle_folder(self, cr, uid, ids, connection, folder, context=None): |
447 | + '''Return ids of objects matched''' |
448 | + |
449 | + matched_object_ids = [] |
450 | + |
451 | + for this in self.browse(cr, uid, ids, context=context): |
452 | + logger.info('start checking for emails in %s server %s', |
453 | + folder.path, this.name) |
454 | + |
455 | + match_algorithm = folder.get_algorithm() |
456 | + |
457 | + if connection.select(folder.path)[0] != 'OK': |
458 | + logger.error( |
459 | + 'Could not open mailbox %s on %s' % ( |
460 | + folder.path, this.server)) |
461 | + connection.select() |
462 | + continue |
463 | + result, msgids = this.get_msgids(connection) |
464 | + if result != 'OK': |
465 | + logger.error( |
466 | + 'Could not search mailbox %s on %s' % ( |
467 | + folder.path, this.server)) |
468 | + continue |
469 | + |
470 | + for msgid in msgids[0].split(): |
471 | + matched_object_ids += this.apply_matching( |
472 | + connection, folder, msgid, match_algorithm) |
473 | + |
474 | + logger.info('finished checking for emails in %s server %s', |
475 | + folder.path, this.name) |
476 | + |
477 | + return matched_object_ids |
478 | + |
479 | + def get_msgids(self, cr, uid, ids, connection, context=None): |
480 | + '''Return imap ids of messages to process''' |
481 | + return connection.search(None, 'UNDELETED') |
482 | + |
483 | + def apply_matching(self, cr, uid, ids, connection, folder, msgid, |
484 | + match_algorithm, context=None): |
485 | + '''Return ids of objects matched''' |
486 | + |
487 | + matched_object_ids = [] |
488 | + |
489 | + for this in self.browse(cr, uid, ids, context=context): |
490 | + result, msgdata = connection.fetch(msgid, '(RFC822)') |
491 | + |
492 | + if result != 'OK': |
493 | + logger.error( |
494 | + 'Could not fetch %s in %s on %s' % ( |
495 | + msgid, folder.path, this.server)) |
496 | + continue |
497 | + |
498 | + mail_message = self.pool.get('mail.message').parse_message( |
499 | + msgdata[0][1], this.original) |
500 | + |
501 | + if self.pool.get('mail.message').search(cr, uid, [ |
502 | + ('message_id', '=', mail_message['message-id'])]): |
503 | + continue |
504 | + |
505 | + found_ids = match_algorithm.search_matches( |
506 | + cr, uid, folder, |
507 | + mail_message, msgdata[0][1]) |
508 | + |
509 | + if found_ids and (len(found_ids) == 1 or |
510 | + folder.match_first): |
511 | + try: |
512 | + cr.execute('savepoint apply_matching') |
513 | + match_algorithm.handle_match( |
514 | + cr, uid, connection, |
515 | + found_ids[0], folder, mail_message, |
516 | + msgdata[0][1], msgid, context) |
517 | + cr.execute('release savepoint apply_matching') |
518 | + matched_object_ids += found_ids[:1] |
519 | + except Exception, e: |
520 | + cr.execute('rollback to savepoint apply_matching') |
521 | + logger.exception( |
522 | + "Failed to fetch mail %s from %s", |
523 | + msgid, this.name) |
524 | + elif folder.flag_nonmatching: |
525 | + connection.store(msgid, '+FLAGS', '\\FLAGGED') |
526 | + |
527 | + return matched_object_ids |
528 | + |
529 | + def attach_mail( |
530 | + self, cr, uid, ids, connection, object_id, folder, |
531 | + mail_message, msgid, context=None): |
532 | + '''Return ids of messages created''' |
533 | + |
534 | + mail_message_ids = [] |
535 | + |
536 | + for this in self.browse(cr, uid, ids, context): |
537 | + partner_id = None |
538 | + if folder.model_id.model == 'res.partner': |
539 | + partner_id = object_id |
540 | + if 'partner_id' in self.pool.get(folder.model_id.model)._columns: |
541 | + partner_id = self.pool.get( |
542 | + folder.model_id.model).browse( |
543 | + cr, uid, object_id, context |
544 | + ).partner_id.id |
545 | + |
546 | + attachments=[] |
547 | + if this.attach and mail_message.get('attachments'): |
548 | + for attachment in mail_message['attachments']: |
549 | + fname, fcontent = attachment |
550 | + if isinstance(fcontent, unicode): |
551 | + fcontent = fcontent.encode('utf-8') |
552 | + data_attach = { |
553 | + 'name': fname, |
554 | + 'datas': base64.b64encode(str(fcontent)), |
555 | + 'datas_fname': fname, |
556 | + 'description': _('Mail attachment'), |
557 | + 'res_model': folder.model_id.model, |
558 | + 'res_id': object_id, |
559 | + } |
560 | + attachments.append( |
561 | + self.pool.get('ir.attachment').create( |
562 | + cr, uid, data_attach, context=context)) |
563 | + |
564 | + mail_message_ids.append( |
565 | + self.pool.get('mail.message').create( |
566 | + cr, uid, |
567 | + { |
568 | + 'partner_id': partner_id, |
569 | + 'model': folder.model_id.model, |
570 | + 'res_id': object_id, |
571 | + 'body_text': mail_message.get('body'), |
572 | + 'body_html': mail_message.get('body_html'), |
573 | + 'subject': mail_message.get('subject'), |
574 | + 'email_to': mail_message.get('to'), |
575 | + 'email_from': mail_message.get('from'), |
576 | + 'email_cc': mail_message.get('cc'), |
577 | + 'reply_to': mail_message.get('reply'), |
578 | + 'date': mail_message.get('date'), |
579 | + 'message_id': mail_message.get('message-id'), |
580 | + 'subtype': mail_message.get('subtype'), |
581 | + 'headers': mail_message.get('headers'), |
582 | + 'state': folder.msg_state, |
583 | + 'attachment_ids': [(6, 0, attachments)], |
584 | + }, |
585 | + context)) |
586 | + |
587 | + if folder.delete_matching: |
588 | + connection.store(msgid, '+FLAGS', '\\DELETED') |
589 | + return mail_message_ids |
590 | + |
591 | + def button_confirm_login(self, cr, uid, ids, context=None): |
592 | + retval = super(fetchmail_server, self).button_confirm_login(cr, uid, |
593 | + ids, |
594 | + context) |
595 | + |
596 | + for this in self.browse(cr, uid, ids, context): |
597 | + this.write({'state': 'draft'}) |
598 | + connection = this.connect() |
599 | + connection.select() |
600 | + for folder in this.folder_ids: |
601 | + if connection.select(folder.path)[0] != 'OK': |
602 | + raise except_orm( |
603 | + _('Error'), _('Mailbox %s not found!') % |
604 | + folder.path) |
605 | + folder.get_algorithm().search_matches( |
606 | + cr, uid, folder, browse_null(), '') |
607 | + connection.close() |
608 | + this.write({'state': 'done'}) |
609 | + |
610 | + return retval |
611 | + |
612 | + def fields_view_get(self, cr, user, view_id=None, view_type='form', |
613 | + context=None, toolbar=False, submenu=False): |
614 | + result = super(fetchmail_server, self).fields_view_get( |
615 | + cr, user, view_id, view_type, context, toolbar, submenu) |
616 | + |
617 | + if view_type == 'form': |
618 | + view = etree.fromstring( |
619 | + result['fields']['folder_ids']['views']['form']['arch']) |
620 | + modifiers = {} |
621 | + docstr = '' |
622 | + for algorithm in self.pool.get('fetchmail.server.folder')\ |
623 | + ._get_match_algorithms().itervalues(): |
624 | + for modifier in ['required', 'readonly']: |
625 | + for field in getattr(algorithm, modifier + '_fields'): |
626 | + modifiers.setdefault(field, {}) |
627 | + modifiers[field].setdefault(modifier, []) |
628 | + if modifiers[field][modifier]: |
629 | + modifiers[field][modifier].insert(0, '|') |
630 | + modifiers[field][modifier].append( |
631 | + ("match_algorithm", "==", algorithm.__name__)) |
632 | + docstr += _(algorithm.name) + '\n' + _(algorithm.__doc__) + \ |
633 | + '\n\n' |
634 | + |
635 | + for field in view: |
636 | + if field.tag == 'field' and field.get('name') in modifiers: |
637 | + field.set('modifiers', simplejson.dumps( |
638 | + dict( |
639 | + eval(field.attrib['modifiers'], |
640 | + UnquoteEvalContext({})), |
641 | + **modifiers[field.attrib['name']]))) |
642 | + if (field.tag == 'field' and |
643 | + field.get('name') == 'match_algorithm'): |
644 | + field.set('help', docstr) |
645 | + result['fields']['folder_ids']['views']['form']['arch'] = \ |
646 | + etree.tostring(view) |
647 | + |
648 | + return result |
649 | |
650 | === added file 'fetchmail_attach_from_folder/model/fetchmail_server_folder.py' |
651 | --- fetchmail_attach_from_folder/model/fetchmail_server_folder.py 1970-01-01 00:00:00 +0000 |
652 | +++ fetchmail_attach_from_folder/model/fetchmail_server_folder.py 2013-04-18 14:54:31 +0000 |
653 | @@ -0,0 +1,120 @@ |
654 | +# -*- encoding: utf-8 -*- |
655 | +############################################################################## |
656 | +# |
657 | +# OpenERP, Open Source Management Solution |
658 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
659 | +# All Rights Reserved |
660 | +# |
661 | +# This program is free software: you can redistribute it and/or modify |
662 | +# it under the terms of the GNU Affero General Public License as |
663 | +# published by the Free Software Foundation, either version 3 of the |
664 | +# License, or (at your option) any later version. |
665 | +# |
666 | +# This program is distributed in the hope that it will be useful, |
667 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
668 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
669 | +# GNU Affero General Public License for more details. |
670 | +# |
671 | +# You should have received a copy of the GNU Affero General Public License |
672 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
673 | +# |
674 | +######################################################################## |
675 | + |
676 | +from openerp.osv import fields |
677 | +from openerp.osv.orm import Model |
678 | +from .. import match_algorithm |
679 | + |
680 | + |
681 | +class fetchmail_server_folder(Model): |
682 | + _name = 'fetchmail.server.folder' |
683 | + _rec_name = 'path' |
684 | + |
685 | + def _get_match_algorithms(self): |
686 | + def get_all_subclasses(cls): |
687 | + return cls.__subclasses__() + [subsub |
688 | + for sub in cls.__subclasses__() |
689 | + for subsub in get_all_subclasses(sub)] |
690 | + return dict([(cls.__name__, cls) for cls in get_all_subclasses( |
691 | + match_algorithm.base.base)]) |
692 | + |
693 | + def _get_match_algorithms_sel(self, cr, uid, context=None): |
694 | + algorithms = [] |
695 | + for cls in self._get_match_algorithms().itervalues(): |
696 | + algorithms.append((cls.__name__, cls.name)) |
697 | + algorithms.sort() |
698 | + return algorithms |
699 | + |
700 | + _columns = { |
701 | + 'sequence': fields.integer('Sequence'), |
702 | + 'path': fields.char( |
703 | + 'Path', size=256, help='The path to your mail ' |
704 | + "folder. Typically would be something like 'INBOX.myfolder'", |
705 | + required=True), |
706 | + 'model_id': fields.many2one( |
707 | + 'ir.model', 'Model', required=True, |
708 | + help='The model to attach emails to'), |
709 | + 'model_field': fields.char( |
710 | + 'Field (model)', size=128, |
711 | + help='The field in your model that contains the field to match ' |
712 | + 'against.\n' |
713 | + 'Examples:\n' |
714 | + "'email' if your model is res.partner, or " |
715 | + "'partner_id.email' if you're matching sale orders"), |
716 | + 'model_order': fields.char( |
717 | + 'Order (model)', size=128, |
718 | + help='Fields to order by, this mostly useful in conjunction ' |
719 | + "with 'Use 1st match'"), |
720 | + 'match_algorithm': fields.selection( |
721 | + _get_match_algorithms_sel, |
722 | + 'Match algorithm', required=True, translate=True, |
723 | + help='The algorithm used to determine which object an email ' |
724 | + 'matches.'), |
725 | + 'mail_field': fields.char( |
726 | + 'Field (email)', size=128, |
727 | + help='The field in the email used for matching. Typically ' |
728 | + "this is 'to' or 'from'"), |
729 | + 'server_id': fields.many2one('fetchmail.server', 'Server'), |
730 | + 'delete_matching': fields.boolean( |
731 | + 'Delete matches', |
732 | + help='Delete matched emails from server'), |
733 | + 'flag_nonmatching': fields.boolean( |
734 | + 'Flag nonmatching', |
735 | + help="Flag emails in the server that don't match any object " |
736 | + 'in OpenERP'), |
737 | + 'match_first': fields.boolean( |
738 | + 'Use 1st match', |
739 | + help='If there are multiple matches, use the first one. If ' |
740 | + 'not checked, multiple matches count as no match at all'), |
741 | + 'domain': fields.char( |
742 | + 'Domain', size=128, help='Fill in a search ' |
743 | + 'filter to narrow down objects to match'), |
744 | + 'msg_state': fields.selection( |
745 | + [ |
746 | + ('sent', 'Sent'), |
747 | + ('received', 'Received'), |
748 | + ], |
749 | + 'Message state', |
750 | + help='The state messages fetched from this folder should be ' |
751 | + 'assigned in OpenERP'), |
752 | + } |
753 | + |
754 | + _defaults = { |
755 | + 'flag_nonmatching': True, |
756 | + 'msg_state': 'received', |
757 | + } |
758 | + |
759 | + def get_algorithm(self, cr, uid, ids, context=None): |
760 | + for this in self.browse(cr, uid, ids, context): |
761 | + return self._get_match_algorithms()[this.match_algorithm]() |
762 | + |
763 | + def button_attach_mail_manually(self, cr, uid, ids, context=None): |
764 | + for this in self.browse(cr, uid, ids, context): |
765 | + context.update({'default_folder_id': this.id}) |
766 | + return { |
767 | + 'type': 'ir.actions.act_window', |
768 | + 'res_model': 'fetchmail.attach.mail.manually', |
769 | + 'target': 'new', |
770 | + 'context': context, |
771 | + 'view_type': 'form', |
772 | + 'view_mode': 'form', |
773 | + } |
774 | |
775 | === added directory 'fetchmail_attach_from_folder/view' |
776 | === added file 'fetchmail_attach_from_folder/view/fetchmail_server.xml' |
777 | --- fetchmail_attach_from_folder/view/fetchmail_server.xml 1970-01-01 00:00:00 +0000 |
778 | +++ fetchmail_attach_from_folder/view/fetchmail_server.xml 2013-04-18 14:54:31 +0000 |
779 | @@ -0,0 +1,58 @@ |
780 | +<?xml version="1.0" encoding="utf-8"?> |
781 | +<openerp> |
782 | + <data> |
783 | + <record model="ir.ui.view" id="view_email_server_form"> |
784 | + <field name="name">fetchmail.server.form</field> |
785 | + <field name="model">fetchmail.server</field> |
786 | + <field name="type">form</field> |
787 | + <field name="inherit_id" ref="fetchmail.view_email_server_form" /> |
788 | + <field name="arch" type="xml"> |
789 | + <data> |
790 | + <field name="object_id" position="attributes"> |
791 | + <attribute name="attrs">{'required': [('type', '!=', 'imap')]}</attribute> |
792 | + </field> |
793 | + <xpath expr="//page[@string='Server & Login']/group[3]" position="after"> |
794 | + <group col="2" colspan="2" attrs="{'invisible': [('type','!=','imap')]}"> |
795 | + <separator string="Folders to monitor" colspan="2"/> |
796 | + <field |
797 | + name="folder_ids" |
798 | + nolabel="1" |
799 | + colspan="2" |
800 | + on_change="onchange_server_type(type, is_ssl, object_id)"> |
801 | + <tree> |
802 | + <field name="sequence" invisible="1" /> |
803 | + <field name="path" /> |
804 | + <field name="model_id" /> |
805 | + <field name="model_field" /> |
806 | + <field name="match_algorithm" /> |
807 | + <field name="mail_field" /> |
808 | + </tree> |
809 | + <form col="6"> |
810 | + <field name="path" /> |
811 | + <field name="model_id" /> |
812 | + <field name="model_field" /> |
813 | + <field name="match_algorithm" /> |
814 | + <field name="mail_field" /> |
815 | + <newline /> |
816 | + <field name="delete_matching" /> |
817 | + <field name="flag_nonmatching" /> |
818 | + <field name="match_first" /> |
819 | + <field name="msg_state" /> |
820 | + <field name="model_order" attrs="{'readonly': [('match_first','==',False)], 'required': [('match_first','==',True)]}" /> |
821 | + <field name="domain" /> |
822 | + <newline /> |
823 | + <label /> |
824 | + <label /> |
825 | + <label /> |
826 | + <label /> |
827 | + <label /> |
828 | + <button type="object" name="button_attach_mail_manually" string="Attach mail manually" icon="gtk-redo" /> |
829 | + </form> |
830 | + </field> |
831 | + </group> |
832 | + </xpath> |
833 | + </data> |
834 | + </field> |
835 | + </record> |
836 | + </data> |
837 | +</openerp> |
838 | |
839 | === added directory 'fetchmail_attach_from_folder/wizard' |
840 | === added file 'fetchmail_attach_from_folder/wizard/__init__.py' |
841 | --- fetchmail_attach_from_folder/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
842 | +++ fetchmail_attach_from_folder/wizard/__init__.py 2013-04-18 14:54:31 +0000 |
843 | @@ -0,0 +1,23 @@ |
844 | +# -*- encoding: utf-8 -*- |
845 | +############################################################################## |
846 | +# |
847 | +# OpenERP, Open Source Management Solution |
848 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
849 | +# All Rights Reserved |
850 | +# |
851 | +# This program is free software: you can redistribute it and/or modify |
852 | +# it under the terms of the GNU Affero General Public License as |
853 | +# published by the Free Software Foundation, either version 3 of the |
854 | +# License, or (at your option) any later version. |
855 | +# |
856 | +# This program is distributed in the hope that it will be useful, |
857 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
858 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
859 | +# GNU Affero General Public License for more details. |
860 | +# |
861 | +# You should have received a copy of the GNU Affero General Public License |
862 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
863 | +# |
864 | +############################################################################## |
865 | + |
866 | +import attach_mail_manually |
867 | |
868 | === added file 'fetchmail_attach_from_folder/wizard/attach_mail_manually.py' |
869 | --- fetchmail_attach_from_folder/wizard/attach_mail_manually.py 1970-01-01 00:00:00 +0000 |
870 | +++ fetchmail_attach_from_folder/wizard/attach_mail_manually.py 2013-04-18 14:54:31 +0000 |
871 | @@ -0,0 +1,110 @@ |
872 | +# -*- encoding: utf-8 -*- |
873 | +############################################################################## |
874 | +# |
875 | +# OpenERP, Open Source Management Solution |
876 | +# This module copyright (C) 2013 Therp BV (<http://therp.nl>) |
877 | +# All Rights Reserved |
878 | +# |
879 | +# This program is free software: you can redistribute it and/or modify |
880 | +# it under the terms of the GNU Affero General Public License as |
881 | +# published by the Free Software Foundation, either version 3 of the |
882 | +# License, or (at your option) any later version. |
883 | +# |
884 | +# This program is distributed in the hope that it will be useful, |
885 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
886 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
887 | +# GNU Affero General Public License for more details. |
888 | +# |
889 | +# You should have received a copy of the GNU Affero General Public License |
890 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
891 | +# |
892 | +############################################################################## |
893 | + |
894 | +from openerp.osv import fields |
895 | +from openerp.osv.orm import TransientModel |
896 | + |
897 | + |
898 | +class attach_mail_manually(TransientModel): |
899 | + _name = 'fetchmail.attach.mail.manually' |
900 | + |
901 | + _columns = { |
902 | + 'folder_id': fields.many2one('fetchmail.server.folder', 'Folder', |
903 | + readonly=True), |
904 | + 'mail_ids': fields.one2many( |
905 | + 'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'), |
906 | + } |
907 | + |
908 | + def default_get(self, cr, uid, fields_list, context=None): |
909 | + if context is None: |
910 | + context = {} |
911 | + |
912 | + defaults = super(attach_mail_manually, self).default_get(cr, uid, |
913 | + fields_list, context) |
914 | + |
915 | + for folder in self.pool.get('fetchmail.server.folder').browse(cr, uid, |
916 | + [context.get('default_folder_id')], context): |
917 | + defaults['mail_ids']=[] |
918 | + connection = folder.server_id.connect() |
919 | + connection.select(folder.path) |
920 | + result, msgids = connection.search(None, |
921 | + 'FLAGGED' if folder.flag_nonmatching else 'UNDELETED') |
922 | + if result != 'OK': |
923 | + logger.error('Could not search mailbox %s on %s' % ( |
924 | + folder.path, this.server)) |
925 | + continue |
926 | + attach_mail_manually_mail._columns['object_id'].selection=[ |
927 | + (folder.model_id.model, folder.model_id.name)] |
928 | + for msgid in msgids[0].split(): |
929 | + result, msgdata = connection.fetch(msgid, '(RFC822)') |
930 | + if result != 'OK': |
931 | + logger.error('Could not fetch %s in %s on %s' % ( |
932 | + msgid, folder.path, this.server)) |
933 | + continue |
934 | + mail_message = self.pool.get('mail.message').parse_message( |
935 | + msgdata[0][1]) |
936 | + defaults['mail_ids'].append((0, 0, { |
937 | + 'msgid': msgid, |
938 | + 'subject': mail_message.get('subject', ''), |
939 | + 'date': mail_message.get('date', ''), |
940 | + 'object_id': folder.model_id.model+',False' |
941 | + })) |
942 | + connection.close() |
943 | + |
944 | + return defaults |
945 | + |
946 | + def attach_mails(self, cr, uid, ids, context=None): |
947 | + for this in self.browse(cr, uid, ids, context): |
948 | + for mail in this.mail_ids: |
949 | + connection = this.folder_id.server_id.connect() |
950 | + connection.select(this.folder_id.path) |
951 | + result, msgdata = connection.fetch(mail.msgid, '(RFC822)') |
952 | + if result != 'OK': |
953 | + logger.error('Could not fetch %s in %s on %s' % ( |
954 | + msgid, folder.path, this.server)) |
955 | + continue |
956 | + |
957 | + mail_message = self.pool.get('mail.message').parse_message( |
958 | + msgdata[0][1], this.folder_id.server_id.original) |
959 | + |
960 | + this.folder_id.server_id.attach_mail(connection, |
961 | + mail.object_id.id, this.folder_id, mail_message, |
962 | + mail.msgid) |
963 | + connection.close() |
964 | + return {'type': 'ir.actions.act_window_close'} |
965 | + |
966 | +class attach_mail_manually_mail(TransientModel): |
967 | + _name = 'fetchmail.attach.mail.manually.mail' |
968 | + |
969 | + _columns = { |
970 | + 'wizard_id': fields.many2one('fetchmail.attach.mail.manually', |
971 | + readonly=True), |
972 | + 'msgid': fields.char('Message id', size=16, readonly=True), |
973 | + 'subject': fields.char('Subject', size=128, readonly=True), |
974 | + 'date': fields.datetime('Date', readonly=True), |
975 | + 'object_id': fields.reference('Object', |
976 | + selection=lambda self, cr, uid, context: |
977 | + [(m.model, m.name) for m in |
978 | + self.pool.get('ir.model').browse(cr, uid, |
979 | + self.pool.get('ir.model').search(cr, uid, []), |
980 | + context)], size=128), |
981 | + } |
982 | |
983 | === added file 'fetchmail_attach_from_folder/wizard/attach_mail_manually.xml' |
984 | --- fetchmail_attach_from_folder/wizard/attach_mail_manually.xml 1970-01-01 00:00:00 +0000 |
985 | +++ fetchmail_attach_from_folder/wizard/attach_mail_manually.xml 2013-04-18 14:54:31 +0000 |
986 | @@ -0,0 +1,26 @@ |
987 | +<?xml version="1.0" encoding="utf-8"?> |
988 | +<openerp> |
989 | + <data> |
990 | + <record model="ir.ui.view" id="view_attach_mail_manually"> |
991 | + <field name="name">fetchmail.attach.mail.manually</field> |
992 | + <field name="model">fetchmail.attach.mail.manually</field> |
993 | + <field name="type">form</field> |
994 | + <field name="arch" type="xml"> |
995 | + <form col="4"> |
996 | + <field name="folder_id" colspan="4" /> |
997 | + <field name="mail_ids" nolabel="1" colspan="4"> |
998 | + <tree editable="top"> |
999 | + <field name="subject" /> |
1000 | + <field name="date" /> |
1001 | + <field name="object_id" /> |
1002 | + </tree> |
1003 | + </field> |
1004 | + <label string="" /> |
1005 | + <label string="" /> |
1006 | + <button special="cancel" string="Cancel" icon="gtk-cancel" /> |
1007 | + <button string="Save" type="object" name="attach_mails" icon="gtk-ok" /> |
1008 | + </form> |
1009 | + </field> |
1010 | + </record> |
1011 | + </data> |
1012 | +</openerp> |
Thanks for taking my comments from https:/ /code.launchpad .net/~therp- nl/server- env-tools/ fetchmail_ attach_ from_folder/ +merge/ 155448 into account