From c63acca18e46bb1f4a71446281dba15aa5e1485f Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 27 Jan 2015 14:57:38 +0100 Subject: [PATCH] [REN] preliminary migration of fetchmail_attach_from_folder --- fetchmail_attach_from_folder/README.rst | 46 +++ fetchmail_attach_from_folder/__init__.py | 25 ++ fetchmail_attach_from_folder/__openerp__.py | 38 +++ .../match_algorithm/__init__.py | 26 ++ .../match_algorithm/base.py | 43 +++ .../match_algorithm/email_domain.py | 45 +++ .../match_algorithm/email_exact.py | 57 ++++ .../match_algorithm/openerp_standard.py | 58 ++++ .../model/__init__.py | 24 ++ .../model/fetchmail_server.py | 263 ++++++++++++++++++ .../model/fetchmail_server_folder.py | 115 ++++++++ .../security/ir.model.access.csv | 2 + .../static/description/icon.png | Bin 0 -> 12585 bytes .../view/fetchmail_server.xml | 56 ++++ .../wizard/__init__.py | 23 ++ .../wizard/attach_mail_manually.py | 129 +++++++++ .../wizard/attach_mail_manually.xml | 29 ++ 17 files changed, 979 insertions(+) create mode 100644 fetchmail_attach_from_folder/README.rst create mode 100644 fetchmail_attach_from_folder/__init__.py create mode 100644 fetchmail_attach_from_folder/__openerp__.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/__init__.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/base.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/email_domain.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/email_exact.py create mode 100644 fetchmail_attach_from_folder/match_algorithm/openerp_standard.py create mode 100644 fetchmail_attach_from_folder/model/__init__.py create mode 100644 fetchmail_attach_from_folder/model/fetchmail_server.py create mode 100644 fetchmail_attach_from_folder/model/fetchmail_server_folder.py create mode 100755 fetchmail_attach_from_folder/security/ir.model.access.csv create mode 100644 fetchmail_attach_from_folder/static/description/icon.png create mode 100644 fetchmail_attach_from_folder/view/fetchmail_server.xml create mode 100644 fetchmail_attach_from_folder/wizard/__init__.py create mode 100644 fetchmail_attach_from_folder/wizard/attach_mail_manually.py create mode 100644 fetchmail_attach_from_folder/wizard/attach_mail_manually.xml diff --git a/fetchmail_attach_from_folder/README.rst b/fetchmail_attach_from_folder/README.rst new file mode 100644 index 000000000..f7380d124 --- /dev/null +++ b/fetchmail_attach_from_folder/README.rst @@ -0,0 +1,46 @@ +Email gateway - folders +======================= + +Adds the possibility to attach emails from a certain IMAP folder to objects, +ie partners. Matching is done via several algorithms, ie email address, email +address's domain or the original Odoo algorithm. + +This gives a simple possibility to archive emails in Odoo without a mail +client integration. + +Configuration +============= + +In your fetchmail configuration, you'll find a new field `folders`. Add your +folders here in IMAP notation [TODO] + +Usage +===== + +A widespread configuration is to have a shared mailbox with several folders [TODO] + +Credits +======= + +Contributors +------------ + +* Holger Brunn + +Icon +---- + +http://commons.wikimedia.org/wiki/File:Crystal_Clear_filesystem_folder_favorites.png + +Maintainer +---------- + +.. image:: http://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: http://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. + +To contribute to this module, please visit http://odoo-community.org. diff --git a/fetchmail_attach_from_folder/__init__.py b/fetchmail_attach_from_folder/__init__.py new file mode 100644 index 000000000..2567300b5 --- /dev/null +++ b/fetchmail_attach_from_folder/__init__.py @@ -0,0 +1,25 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import match_algorithm +from . import model +from . import wizard diff --git a/fetchmail_attach_from_folder/__openerp__.py b/fetchmail_attach_from_folder/__openerp__.py new file mode 100644 index 000000000..93b0a022c --- /dev/null +++ b/fetchmail_attach_from_folder/__openerp__.py @@ -0,0 +1,38 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Email gateway - folders', + 'summary': 'Attach mails in an IMAP folder to existing objects', + 'version': '1.0', + 'author': 'Therp BV', + 'website': 'http://www.therp.nl', + "category": "Tools", + "depends": ['fetchmail'], + 'data': [ + 'view/fetchmail_server.xml', + 'wizard/attach_mail_manually.xml', + 'security/ir.model.access.csv', + ], + 'installable': True, + 'active': True, +} diff --git a/fetchmail_attach_from_folder/match_algorithm/__init__.py b/fetchmail_attach_from_folder/match_algorithm/__init__.py new file mode 100644 index 000000000..baa099c37 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/__init__.py @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import base +from . import email_exact +from . import email_domain +from . import openerp_standard diff --git a/fetchmail_attach_from_folder/match_algorithm/base.py b/fetchmail_attach_from_folder/match_algorithm/base.py new file mode 100644 index 000000000..34e7b3dbe --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/base.py @@ -0,0 +1,43 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +class base(object): + name = None + '''Name shown to the user''' + + required_fields = [] + '''Fields on fetchmail_server folder required for this algorithm''' + + readonly_fields = [] + '''Fields on fetchmail_server folder readonly for this algorithm''' + + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): + '''Returns ids found for model with mail_message''' + return [] + + def handle_match( + self, cr, uid, connection, object_id, folder, + mail_message, mail_message_org, msgid, context=None): + '''Do whatever it takes to handle a match''' + return folder.server_id.attach_mail(connection, object_id, folder, + mail_message, msgid) diff --git a/fetchmail_attach_from_folder/match_algorithm/email_domain.py b/fetchmail_attach_from_folder/match_algorithm/email_domain.py new file mode 100644 index 000000000..1f06b7e7c --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/email_domain.py @@ -0,0 +1,45 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from .email_exact import email_exact + + +class email_domain(email_exact): + '''Search objects by domain name of email address. + Beware of match_first here, this is most likely to get it wrong (gmail)''' + name = 'Domain of email address' + + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): + ids = super(email_domain, self).search_matches( + cr, uid, conf, mail_message, mail_message_org) + if not ids: + domains = [] + for addr in self._get_mailaddresses(conf, mail_message): + domains.append(addr.split('@')[-1]) + ids = conf.pool.get(conf.model_id.model).search( + cr, uid, + self._get_mailaddress_search_domain( + conf, mail_message, + operator='like', + values=['%@' + domain for domain in set(domains)]), + order=conf.model_order) + return ids diff --git a/fetchmail_attach_from_folder/match_algorithm/email_exact.py b/fetchmail_attach_from_folder/match_algorithm/email_exact.py new file mode 100644 index 000000000..a2225e083 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/email_exact.py @@ -0,0 +1,57 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from .base import base +from openerp.tools.safe_eval import safe_eval +from openerp.tools.mail import email_split + + +class email_exact(base): + '''Search for exactly the mailadress as noted in the email''' + + name = 'Exact mailadress' + required_fields = ['model_field', 'mail_field'] + + def _get_mailaddresses(self, conf, mail_message): + mailaddresses = [] + fields = conf.mail_field.split(',') + for field in fields: + if field in mail_message: + mailaddresses += email_split(mail_message[field]) + return [addr.lower() for addr in mailaddresses] + + def _get_mailaddress_search_domain( + self, conf, mail_message, operator='=', values=None): + mailaddresses = values or self._get_mailaddresses( + conf, mail_message) + if not mailaddresses: + return [(0, '=', 1)] + search_domain = ((['|'] * (len(mailaddresses) - 1)) + [ + (conf.model_field, operator, addr) for addr in mailaddresses] + + safe_eval(conf.domain or '[]')) + return search_domain + + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): + conf_model = conf.pool.get(conf.model_id.model) + search_domain = self._get_mailaddress_search_domain(conf, mail_message) + return conf_model.search( + cr, uid, search_domain, order=conf.model_order) diff --git a/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py b/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py new file mode 100644 index 000000000..217699169 --- /dev/null +++ b/fetchmail_attach_from_folder/match_algorithm/openerp_standard.py @@ -0,0 +1,58 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from .base import base + + +class openerp_standard(base): + '''No search at all. Use OpenERP's standard mechanism to attach mails to + mail.thread objects. Note that this algorithm always matches.''' + + name = 'OpenERP standard' + readonly_fields = [ + 'model_field', + 'mail_field', + 'match_first', + 'domain', + 'model_order', + 'flag_nonmatching', + ] + + def search_matches(self, cr, uid, conf, mail_message, mail_message_org): + '''Always match. Duplicates will be fished out by message_id''' + return [True] + + def handle_match( + self, cr, uid, connection, object_id, folder, + mail_message, mail_message_org, msgid, context): + result = folder.pool.get('mail.thread').message_process( + cr, uid, + folder.model_id.model, mail_message_org, + save_original=folder.server_id.original, + strip_attachments=(not folder.server_id.attach), + context=context + ) + + if folder.delete_matching: + connection.store(msgid, '+FLAGS', '\\DELETED') + + return [result] diff --git a/fetchmail_attach_from_folder/model/__init__.py b/fetchmail_attach_from_folder/model/__init__.py new file mode 100644 index 000000000..1073e5e38 --- /dev/null +++ b/fetchmail_attach_from_folder/model/__init__.py @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import fetchmail_server +from . import fetchmail_server_folder diff --git a/fetchmail_attach_from_folder/model/fetchmail_server.py b/fetchmail_attach_from_folder/model/fetchmail_server.py new file mode 100644 index 000000000..60dbdce94 --- /dev/null +++ b/fetchmail_attach_from_folder/model/fetchmail_server.py @@ -0,0 +1,263 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +import logging +import base64 +import simplejson +from lxml import etree +from openerp import models, fields, api, exceptions +from openerp.tools.translate import _ +from openerp.tools.misc import UnquoteEvalContext + + +class fetchmail_server(models.Model): + _inherit = 'fetchmail.server' + + folder_ids = fields.One2many( + 'fetchmail.server.folder', 'server_id', 'Folders') + object_id = fields.Many2one(required=True) + + _defaults = { + 'type': 'imap', + } + + def onchange_server_type( + self, cr, uid, ids, server_type=False, ssl=False, + object_id=False): + retval = super( + fetchmail_server, self).onchange_server_type(cr, uid, + ids, server_type, ssl, + object_id) + retval['value']['state'] = 'draft' + return retval + + def fetch_mail(self, cr, uid, ids, context=None): + if context is None: + context = {} + + check_original = [] + + for this in self.browse(cr, uid, ids, context): + if this.object_id: + check_original.append(this.id) + + context.update( + { + 'fetchmail_server_id': this.id, + 'server_type': this.type + }) + + connection = this.connect() + for folder in this.folder_ids: + this.handle_folder(connection, folder) + connection.close() + + return super(fetchmail_server, self).fetch_mail( + cr, uid, check_original, context) + + @api.multi + def handle_folder(self, connection, folder): + '''Return ids of objects matched''' + + matched_object_ids = [] + + for this in self: + logging.info( + 'start checking for emails in %s server %s', + folder.path, this.name) + + match_algorithm = folder.get_algorithm() + + if connection.select(folder.path)[0] != 'OK': + logging.error( + 'Could not open mailbox %s on %s', + folder.path, this.server) + connection.select() + continue + result, msgids = this.get_msgids(connection) + if result != 'OK': + logging.error( + 'Could not search mailbox %s on %s', + folder.path, this.server) + continue + + for msgid in msgids[0].split(): + matched_object_ids += this.apply_matching( + connection, folder, msgid, match_algorithm) + + logging.info( + 'finished checking for emails in %s server %s', + folder.path, this.name) + + return matched_object_ids + + @api.multi + def get_msgids(self, connection): + '''Return imap ids of messages to process''' + return connection.search(None, 'UNDELETED') + + @api.multi + def apply_matching(self, connection, folder, msgid, match_algorithm): + '''Return ids of objects matched''' + + matched_object_ids = [] + + for this in self: + result, msgdata = connection.fetch(msgid, '(RFC822)') + + if result != 'OK': + logging.error( + 'Could not fetch %s in %s on %s', + msgid, folder.path, this.server) + continue + + mail_message = self.env['mail.thread'].message_parse( + msgdata[0][1], save_original=this.original) + + if self.env['mail.message'].search( + [('message_id', '=', mail_message['message_id'])]): + continue + + found_ids = match_algorithm.search_matches( + self.env.cr, self.env.uid, folder, mail_message, msgdata[0][1]) + + if found_ids and (len(found_ids) == 1 or + folder.match_first): + try: + self.env.cr.execute('savepoint apply_matching') + match_algorithm.handle_match( + self.env.cr, self.env.uid, connection, + found_ids[0], folder, mail_message, + msgdata[0][1], msgid, self.env.context) + self.env.cr.execute('release savepoint apply_matching') + matched_object_ids += found_ids[:1] + except Exception: + self.env.cr.execute('rollback to savepoint apply_matching') + logging.exception( + "Failed to fetch mail %s from %s", msgid, this.name) + elif folder.flag_nonmatching: + connection.store(msgid, '+FLAGS', '\\FLAGGED') + + return matched_object_ids + + @api.multi + def attach_mail(self, connection, object_id, folder, mail_message, msgid): + '''Return ids of messages created''' + + mail_message_ids = [] + + for this in self: + partner_id = None + if folder.model_id.model == 'res.partner': + partner_id = object_id + if 'partner_id' in self.env[folder.model_id.model]._columns: + partner_id = self.env[folder.model_id.model].browse(object_id)\ + .partner_id.id + + attachments = [] + if this.attach and mail_message.get('attachments'): + for attachment in mail_message['attachments']: + fname, fcontent = attachment + if isinstance(fcontent, unicode): + fcontent = fcontent.encode('utf-8') + data_attach = { + 'name': fname, + 'datas': base64.b64encode(str(fcontent)), + 'datas_fname': fname, + 'description': _('Mail attachment'), + 'res_model': folder.model_id.model, + 'res_id': object_id, + } + attachments.append( + self.env['ir.attachment'].create(data_attach)) + + mail_message_ids.append( + self.env['mail.message'].create({ + 'author_id': partner_id, + 'model': folder.model_id.model, + 'res_id': object_id, + 'type': 'email', + 'body': mail_message.get('body'), + 'subject': mail_message.get('subject'), + 'email_from': mail_message.get('from'), + 'date': mail_message.get('date'), + 'message_id': mail_message.get('message_id'), + 'attachment_ids': [(6, 0, [a.id for a in attachments])], + })) + + if folder.delete_matching: + connection.store(msgid, '+FLAGS', '\\DELETED') + return mail_message_ids + + def button_confirm_login(self, cr, uid, ids, context=None): + retval = super(fetchmail_server, self).button_confirm_login( + cr, uid, ids, context) + + for this in self.browse(cr, uid, ids, context): + this.write({'state': 'draft'}) + connection = this.connect() + connection.select() + for folder in this.folder_ids: + if connection.select(folder.path)[0] != 'OK': + raise exceptions.ValidationError( + _('Mailbox %s not found!') % folder.path) + connection.close() + this.write({'state': 'done'}) + + return retval + + def fields_view_get(self, cr, user, view_id=None, view_type='form', + context=None, toolbar=False, submenu=False): + result = super(fetchmail_server, self).fields_view_get( + cr, user, view_id, view_type, context, toolbar, submenu) + + if view_type == 'form': + view = etree.fromstring( + result['fields']['folder_ids']['views']['form']['arch']) + modifiers = {} + docstr = '' + for algorithm in self.pool['fetchmail.server.folder']\ + ._get_match_algorithms().itervalues(): + for modifier in ['required', 'readonly']: + for field in getattr(algorithm, modifier + '_fields'): + modifiers.setdefault(field, {}) + modifiers[field].setdefault(modifier, []) + if modifiers[field][modifier]: + modifiers[field][modifier].insert(0, '|') + modifiers[field][modifier].append( + ("match_algorithm", "==", algorithm.__name__)) + docstr += _(algorithm.name) + '\n' + _(algorithm.__doc__) + \ + '\n\n' + + for field in view.xpath('//field'): + if field.tag == 'field' and field.get('name') in modifiers: + field.set('modifiers', simplejson.dumps( + dict( + eval(field.attrib['modifiers'], + UnquoteEvalContext({})), + **modifiers[field.attrib['name']]))) + if (field.tag == 'field' and + field.get('name') == 'match_algorithm'): + field.set('help', docstr) + result['fields']['folder_ids']['views']['form']['arch'] = \ + etree.tostring(view) + + return result diff --git a/fetchmail_attach_from_folder/model/fetchmail_server_folder.py b/fetchmail_attach_from_folder/model/fetchmail_server_folder.py new file mode 100644 index 000000000..570245572 --- /dev/null +++ b/fetchmail_attach_from_folder/model/fetchmail_server_folder.py @@ -0,0 +1,115 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +######################################################################## +from openerp import api, models, fields +from .. import match_algorithm + + +class fetchmail_server_folder(models.Model): + _name = 'fetchmail.server.folder' + _rec_name = 'path' + + def _get_match_algorithms(self): + def get_all_subclasses(cls): + return (cls.__subclasses__() + + [subsub + for sub in cls.__subclasses__() + for subsub in get_all_subclasses(sub)]) + return dict([(cls.__name__, cls) + for cls in get_all_subclasses( + match_algorithm.base.base)]) + + def _get_match_algorithms_sel(self): + algorithms = [] + for cls in self._get_match_algorithms().itervalues(): + algorithms.append((cls.__name__, cls.name)) + algorithms.sort() + return algorithms + + sequence = fields.Integer('Sequence') + path = fields.Char( + 'Path', + help="The path to your mail folder. Typically would be something like " + "'INBOX.myfolder'", required=True) + model_id = fields.Many2one( + 'ir.model', 'Model', required=True, + help='The model to attach emails to') + model_field = fields.Char( + 'Field (model)', + help='The field in your model that contains the field to match ' + 'against.\n' + 'Examples:\n' + "'email' if your model is res.partner, or " + "'partner_id.email' if you're matching sale orders") + model_order = fields.Char( + 'Order (model)', + help='Field(s) to order by, this mostly useful in conjunction ' + "with 'Use 1st match'") + match_algorithm = fields.Selection( + _get_match_algorithms_sel, + 'Match algorithm', required=True, + help='The algorithm used to determine which object an email matches.') + mail_field = fields.Char( + 'Field (email)', + help='The field in the email used for matching. Typically ' + "this is 'to' or 'from'") + server_id = fields.Many2one('fetchmail.server', 'Server') + delete_matching = fields.Boolean( + 'Delete matches', + help='Delete matched emails from server') + flag_nonmatching = fields.Boolean( + 'Flag nonmatching', + help="Flag emails in the server that don't match any object in Odoo") + match_first = fields.Boolean( + 'Use 1st match', + help='If there are multiple matches, use the first one. If ' + 'not checked, multiple matches count as no match at all') + domain = fields.Char( + 'Domain', + help='Fill in a search filter to narrow down objects to match') + msg_state = fields.Selection( + [ + ('sent', 'Sent'), + ('received', 'Received'), + ], + 'Message state', + help='The state messages fetched from this folder should be ' + 'assigned in Odoo') + + _defaults = { + 'flag_nonmatching': True, + 'msg_state': 'received', + } + + @api.multi + def get_algorithm(self): + return self._get_match_algorithms()[self.match_algorithm]() + + @api.multi + def button_attach_mail_manually(self): + return { + 'type': 'ir.actions.act_window', + 'res_model': 'fetchmail.attach.mail.manually', + 'target': 'new', + 'context': dict(self.env.context, default_folder_id=self.id), + 'view_type': 'form', + 'view_mode': 'form', + } diff --git a/fetchmail_attach_from_folder/security/ir.model.access.csv b/fetchmail_attach_from_folder/security/ir.model.access.csv new file mode 100755 index 000000000..c63f46bb8 --- /dev/null +++ b/fetchmail_attach_from_folder/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_model_fetchmail_server_folder,fetchmail.server.folder,model_fetchmail_server_folder,base.group_system,1,1,1,1 diff --git a/fetchmail_attach_from_folder/static/description/icon.png b/fetchmail_attach_from_folder/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..be54e22b8851ded0aa8c0b0f1a016f2631b8f8a3 GIT binary patch literal 12585 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
    qqW8o`fjhYut8Px(1DfDuZqyuEthX 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 literal 0 HcmV?d00001 diff --git a/fetchmail_attach_from_folder/view/fetchmail_server.xml b/fetchmail_attach_from_folder/view/fetchmail_server.xml new file mode 100644 index 000000000..49384b039 --- /dev/null +++ b/fetchmail_attach_from_folder/view/fetchmail_server.xml @@ -0,0 +1,56 @@ + + + + + fetchmail.server.form + fetchmail.server + + + + + {'required': [('type', '!=', 'imap')]} + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/fetchmail_attach_from_folder/wizard/__init__.py b/fetchmail_attach_from_folder/wizard/__init__.py new file mode 100644 index 000000000..1f98c5a26 --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import attach_mail_manually diff --git a/fetchmail_attach_from_folder/wizard/attach_mail_manually.py b/fetchmail_attach_from_folder/wizard/attach_mail_manually.py new file mode 100644 index 000000000..0c22f0c86 --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/attach_mail_manually.py @@ -0,0 +1,129 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2013 Therp BV () +# All Rights Reserved +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import fields +from openerp.osv.orm import TransientModel +import logging +logger = logging.getLogger(__name__) + + +class attach_mail_manually(TransientModel): + _name = 'fetchmail.attach.mail.manually' + + _columns = { + 'folder_id': fields.many2one('fetchmail.server.folder', 'Folder', + readonly=True), + 'mail_ids': fields.one2many( + 'fetchmail.attach.mail.manually.mail', 'wizard_id', 'Emails'), + } + + def default_get(self, cr, uid, fields_list, context=None): + if context is None: + context = {} + + defaults = super(attach_mail_manually, self).default_get( + cr, uid, fields_list, context + ) + + for folder in self.pool.get('fetchmail.server.folder').browse( + cr, uid, + [context.get('default_folder_id')], context): + defaults['mail_ids'] = [] + connection = folder.server_id.connect() + connection.select(folder.path) + result, msgids = connection.search( + None, + 'FLAGGED' if folder.flag_nonmatching else 'UNDELETED') + if result != 'OK': + logger.error('Could not search mailbox %s on %s' % ( + folder.path, folder.server_id.name)) + continue + attach_mail_manually_mail._columns['object_id'].selection = [ + (folder.model_id.model, folder.model_id.name)] + for msgid in msgids[0].split(): + result, msgdata = connection.fetch(msgid, '(RFC822)') + if result != 'OK': + logger.error('Could not fetch %s in %s on %s' % ( + msgid, folder.path, folder.server_id.name)) + continue + mail_message = self.pool.get('mail.thread').message_parse( + cr, uid, msgdata[0][1], + save_original=folder.server_id.original, + context=context + ) + defaults['mail_ids'].append((0, 0, { + 'msgid': msgid, + 'subject': mail_message.get('subject', ''), + 'date': mail_message.get('date', ''), + 'object_id': folder.model_id.model + ',False' + })) + connection.close() + + return defaults + + def attach_mails(self, cr, uid, ids, context=None): + for this in self.browse(cr, uid, ids, context): + for mail in this.mail_ids: + connection = this.folder_id.server_id.connect() + connection.select(this.folder_id.path) + result, msgdata = connection.fetch(mail.msgid, '(RFC822)') + if result != 'OK': + logger.error('Could not fetch %s in %s on %s' % ( + mail.msgid, this.folder_id.path, this.server)) + continue + + mail_message = self.pool.get('mail.thread').message_parse( + cr, uid, msgdata[0][1], + save_original=this.folder_id.server_id.original, + context=context) + + this.folder_id.server_id.attach_mail( + connection, + mail.object_id.id, this.folder_id, mail_message, + mail.msgid + ) + connection.close() + return {'type': 'ir.actions.act_window_close'} + + +class attach_mail_manually_mail(TransientModel): + _name = 'fetchmail.attach.mail.manually.mail' + + _columns = { + 'wizard_id': fields.many2one('fetchmail.attach.mail.manually', + readonly=True), + 'msgid': fields.char('Message id', size=16, readonly=True), + 'subject': fields.char('Subject', size=128, readonly=True), + 'date': fields.datetime('Date', readonly=True), + 'object_id': fields.reference( + 'Object', + selection=lambda self, cr, uid, context: [ + (m.model, m.name) + for m in self.pool.get('ir.model').browse( + cr, uid, + self.pool.get('ir.model').search(cr, uid, []), + context + ) + ], + size=128, + ), + } diff --git a/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml b/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml new file mode 100644 index 000000000..fbe82eea7 --- /dev/null +++ b/fetchmail_attach_from_folder/wizard/attach_mail_manually.xml @@ -0,0 +1,29 @@ + + + + + fetchmail.attach.mail.manually + fetchmail.attach.mail.manually + +
    + + + + + + + + + + + + + +
    +
    +
    +
    +