From 052a05902927c59f4eec9e5ee1916fba13841b79 Mon Sep 17 00:00:00 2001 From: "YSA (Openerp)" Date: Wed, 2 Feb 2011 14:10:29 +0530 Subject: [PATCH] [IMP] improve email, email_gateway and email_template module. bzr revid: ysa@tinyerp.com-20110202084029-do4g3euykt5k79gd --- addons/email/__init__.py | 4 +- addons/email/__openerp__.py | 5 +- .../email_gateway_scheduler_data.xml | 0 addons/email/email_message.py | 267 ++++++++ addons/email/email_message_view.xml | 128 ++++ addons/email/email_smtp_server.py | 34 +- addons/email/email_view.xml | 96 --- addons/email/emails.py | 489 ------------- addons/email/res_partner.py | 2 +- addons/email/security/ir.model.access.csv | 1 - addons/email_gateway/__openerp__.py | 4 +- addons/email_gateway/email_gateway.py | 645 ++++++++++++------ addons/email_gateway/email_gateway_view.xml | 169 ++--- addons/email_template/email_template.py | 58 +- .../wizard/email_template_preview.py | 1 + .../wizard/email_template_send_wizard.py | 18 +- 16 files changed, 941 insertions(+), 980 deletions(-) rename addons/{email_gateway => email}/email_gateway_scheduler_data.xml (100%) create mode 100644 addons/email/email_message.py create mode 100644 addons/email/email_message_view.xml delete mode 100644 addons/email/email_view.xml delete mode 100644 addons/email/emails.py diff --git a/addons/email/__init__.py b/addons/email/__init__.py index b78d77029a9..5e481d8e957 100644 --- a/addons/email/__init__.py +++ b/addons/email/__init__.py @@ -19,9 +19,9 @@ # ############################################################################## -import emails -import res_partner import email_smtp_server +import email_message +import res_partner # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/email/__openerp__.py b/addons/email/__openerp__.py index 6ef5c3183ef..024292f5d27 100644 --- a/addons/email/__openerp__.py +++ b/addons/email/__openerp__.py @@ -31,11 +31,12 @@ 'depends': ['base', 'base_tools'], 'init_xml': [], 'update_xml': [ - "email_view.xml", + "email_message_view.xml", "res_partner_view.xml", 'email_smtp_server_view.xml', 'security/ir.model.access.csv', - 'email_smtp_server_data.xml' + 'email_smtp_server_data.xml', + 'email_gateway_scheduler_data.xml', ], 'demo_xml': [], diff --git a/addons/email_gateway/email_gateway_scheduler_data.xml b/addons/email/email_gateway_scheduler_data.xml similarity index 100% rename from addons/email_gateway/email_gateway_scheduler_data.xml rename to addons/email/email_gateway_scheduler_data.xml diff --git a/addons/email/email_message.py b/addons/email/email_message.py new file mode 100644 index 00000000000..5cfeafd49f2 --- /dev/null +++ b/addons/email/email_message.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL () +# +# 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 osv import osv, fields +import time +import tools +import binascii +import email +from email.header import decode_header +from email.utils import parsedate +import base64 +import re +from tools.translate import _ +import logging +import xmlrpclib + +_logger = logging.getLogger('mailgate') + +def format_date_tz(date, tz=None): + if not date: + return 'n/a' + format = tools.DEFAULT_SERVER_DATETIME_FORMAT + return tools.server_to_local_timestamp(date, format, format, tz) + +class email_message(osv.osv): + ''' + Email Message + ''' + _name = 'email.message' + _description = 'Email Message' + _order = 'date desc' + + def open_document(self, cr, uid, ids, context=None): + """ To Open Document + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param ids: the ID of messages + @param context: A standard dictionary + """ + action_data = False + if ids: + message_id = ids[0] + mailgate_data = self.browse(cr, uid, message_id, context=context) + model = mailgate_data.model + res_id = mailgate_data.res_id + + action_pool = self.pool.get('ir.actions.act_window') + action_ids = action_pool.search(cr, uid, [('res_model', '=', model)]) + if action_ids: + action_data = action_pool.read(cr, uid, action_ids[0], context=context) + action_data.update({ + 'domain' : "[('id','=',%d)]"%(res_id), + 'nodestroy': True, + 'context': {} + }) + return action_data + + def open_attachment(self, cr, uid, ids, context=None): + """ To Open attachments + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param ids: the ID of messages + @param context: A standard dictionary + """ + action_data = False + action_pool = self.pool.get('ir.actions.act_window') + message_pool = self.browse(cr ,uid, ids, context=context)[0] + att_ids = [x.id for x in message_pool.attachment_ids] + action_ids = action_pool.search(cr, uid, [('res_model', '=', 'ir.attachment')]) + if action_ids: + action_data = action_pool.read(cr, uid, action_ids[0], context=context) + action_data.update({ + 'domain': [('id','in',att_ids)], + 'nodestroy': True + }) + return action_data + + def truncate_data(self, cr, uid, data, context=None): + data_list = data and data.split('\n') or [] + if len(data_list) > 3: + res = '\n\t'.join(data_list[:3]) + '...' + else: + res = '\n\t'.join(data_list) + return res + + def _get_display_text(self, cr, uid, ids, name, arg, context=None): + if context is None: + context = {} + tz = context.get('tz') + result = {} + for message in self.browse(cr, uid, ids, context=context): + msg_txt = '' + if message.history: + msg_txt += (message.email_from or '/') + _(' wrote on ') + format_date_tz(message.date, tz) + ':\n\t' + if message.description: + msg_txt += self.truncate_data(cr, uid, message.description, context=context) + else: + msg_txt = (message.user_id.name or '/') + _(' on ') + format_date_tz(message.date, tz) + ':\n\t' + if message.name == _('Opportunity'): + msg_txt += _("Converted to Opportunity") + elif message.name == _('Note'): + msg_txt = (message.user_id.name or '/') + _(' added note on ') + format_date_tz(message.date, tz) + ':\n\t' + msg_txt += self.truncate_data(cr, uid, message.description, context=context) + elif message.name == _('Stage'): + msg_txt += _("Changed Stage to: ") + message.description + else: + msg_txt += _("Changed Status to: ") + message.name + result[message.id] = msg_txt + return result + + _columns = { + 'name':fields.text('Subject', readonly=True), + 'model': fields.char('Object Name', size=128, select=1, readonly=True), + 'res_id': fields.integer('Resource ID', select=1, readonly=True), + 'ref_id': fields.char('Reference Id', size=256, readonly=True, help="Message Id in Email Server.", select=True), + 'date': fields.datetime('Date', readonly=True), + 'history': fields.boolean('Is History?', readonly=True), + 'user_id': fields.many2one('res.users', 'User Responsible', readonly=True), + 'message': fields.text('Description', readonly=True), + 'email_from': fields.char('From', size=128, help="Email From", readonly=True), + 'email_to': fields.char('To', help="Email Recipients", size=256, readonly=True), + 'email_cc': fields.char('Cc', help="Carbon Copy Email Recipients", size=256, readonly=True), + 'email_bcc': fields.char('Bcc', help='Blind Carbon Copy Email Recipients', size=256, readonly=True), + 'message_id': fields.char('Message Id', size=1024, readonly=True, help="Message Id on Email.", select=True), + 'references': fields.text('References', readonly=True, help="References emails."), + 'description': fields.text('Description', readonly=True), + 'partner_id': fields.many2one('res.partner', 'Partner', required=False), + 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments', readonly=True), + 'display_text': fields.function(_get_display_text, method=True, type='text', size="512", string='Display Text'), + 'reply_to':fields.char('Reply-To', size=250, readonly=True), + 'account_id' :fields.many2one('email.smtp_server', 'User account', required=True, readonly=True), + #I like GMAIL which allows putting same mail in many folders + #Lets plan it for 0.9 + 'folder':fields.selection([ + ('drafts', 'Drafts'), + ('outbox', 'Outbox'), + ('trash', 'Trash'), + ('sent', 'Sent Items'), + ], 'Folder', required=True, readonly=True), + 'state':fields.selection([ + ('na', 'Not Applicable'), + ('sending', 'Sending'), + ('wait', 'Waiting'), + ], 'Status', required=True, readonly=True), + } + + _defaults = { + 'state': lambda * a: 'na', + 'folder': lambda * a: 'outbox', + } + + def unlink(self, cr, uid, ids, context=None): + """ + It just changes the folder of the item to "Trash", if it is no in Trash folder yet, + or completely deletes it if it is already in Trash. + """ + to_update = [] + to_remove = [] + for mail in self.browse(cr, uid, ids, context=context): + if mail.folder == 'trash': + to_remove.append(mail.id) + else: + to_update.append(mail.id) + # Changes the folder to trash + self.write(cr, uid, to_update, {'folder': 'trash'}, context=context) + return super(email_template_mailbox, self).unlink(cr, uid, to_remove, context=context) + + def init(self, cr): + cr.execute("""SELECT indexname + FROM pg_indexes + WHERE indexname = 'email_message_res_id_model_idx'""") + if not cr.fetchone(): + cr.execute("""CREATE INDEX email_message_res_id_model_idx + ON email_message (model, res_id)""") + + def run_mail_scheduler(self, cursor, user, context=None): + """ + This method is called by OpenERP Scheduler + to periodically send emails + """ + try: + self.send_all_mail(cursor, user, context=context) + except Exception, e: + LOGGER.notifyChannel( + "Email Template", + netsvc.LOG_ERROR, + _("Error sending mail: %s") % e) + + def send_all_mail(self, cr, uid, ids=None, context=None): + if ids is None: + ids = [] + if context is None: + context = {} + filters = [('folder', '=', 'outbox'), ('state', '!=', 'sending')] + if 'filters' in context.keys(): + for each_filter in context['filters']: + filters.append(each_filter) + ids = self.search(cr, uid, filters, context=context) + self.write(cr, uid, ids, {'state':'sending'}, context) + self.send_this_mail(cr, uid, ids, context) + return True + + def send_this_mail(self, cr, uid, ids=None, context=None): + #previous method to send email (link with email account can be found at the revision 4172 and below + result = True + attachment_pool = self.pool.get('ir.attachment') + for id in (ids or []): + try: + account_obj = self.pool.get('email.smtp_server') + values = self.read(cr, uid, id, [], context) + payload = {} + if values['attachments_ids']: + for attid in values['attachments_ids']: + attachment = attachment_pool.browse(cr, uid, attid, context)#,['datas_fname','datas']) + payload[attachment.datas_fname] = attachment.datas + result = account_obj.send_mail(cr, uid, + [values['account_id'][0]], + {'To':values.get('email_to') or u'', + 'CC':values.get('email_cc') or u'', + 'BCC':values.get('email_bcc') or u'', + 'Reply-To':values.get('reply_to') or u''}, + values['subject'] or u'', + {'text':values.get('body_text') or u'', 'html':values.get('body_html') or u''}, + payload=payload, + message_id=values['message_id'], + context=context) + if result == True: + account = account_obj.browse(cr, uid, values['account_id'][0], context=context) + if account.auto_delete: + self.write(cr, uid, id, {'folder': 'trash'}, context=context) + self.unlink(cr, uid, [id], context=context) + # Remove attachments for this mail + attachment_pool.unlink(cr, uid, values['attachments_ids'], context=context) + else: + self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context) + else: + error = result['error_msg'] + + except Exception, error: + logger = netsvc.Logger() + logger.notifyChannel("email-template", netsvc.LOG_ERROR, _("Sending of Mail %s failed. Probable Reason:Could not login to server\nError: %s") % (id, error)) + self.write(cr, uid, id, {'state':'na'}, context) + return result + +email_message() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/email/email_message_view.xml b/addons/email/email_message_view.xml new file mode 100644 index 00000000000..1478fe452ec --- /dev/null +++ b/addons/email/email_message_view.xml @@ -0,0 +1,128 @@ + + + + + + + + email.message.form + email.message + form + +
+ + + + + + + + + + + + + + + + + + + + + +