need just fix rendering
This commit is contained in:
parent
aa4fbe72ec
commit
45ab7611a3
1 changed files with 43 additions and 144 deletions
|
|
@ -50,7 +50,7 @@ class IrAttachment(models.Model):
|
||||||
return ' '.join(str(value).split())
|
return ' '.join(str(value).split())
|
||||||
|
|
||||||
def process_msg_as_email(self):
|
def process_msg_as_email(self):
|
||||||
"""Convert MSG file to standard email format and process it using Odoo's mail module."""
|
"""Convert MSG file to RFC822 email format and process it using Odoo's mail module."""
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
_logger.info('Starting MSG processing for file: %s (model: %s, res_id: %s)',
|
_logger.info('Starting MSG processing for file: %s (model: %s, res_id: %s)',
|
||||||
self.name, self.res_model, self.res_id)
|
self.name, self.res_model, self.res_id)
|
||||||
|
|
@ -61,16 +61,6 @@ class IrAttachment(models.Model):
|
||||||
_('The selected file is not a valid MSG file'))
|
_('The selected file is not a valid MSG file'))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self.datas:
|
|
||||||
try:
|
|
||||||
# Try to reload data from filestore
|
|
||||||
self.datas = self.datas
|
|
||||||
except Exception as e:
|
|
||||||
_logger.error('Failed to read file %s from filestore: %s', self.name, str(e))
|
|
||||||
self._notify_error('File Access Error',
|
|
||||||
_('The MSG file could not be read from the filestore. The file may have been moved or deleted.'))
|
|
||||||
return False
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Read the MSG file
|
# Read the MSG file
|
||||||
_logger.info('Decoding MSG file data')
|
_logger.info('Decoding MSG file data')
|
||||||
|
|
@ -81,86 +71,58 @@ class IrAttachment(models.Model):
|
||||||
|
|
||||||
# Convert MSG to email format
|
# Convert MSG to email format
|
||||||
email_msg = EmailMessage()
|
email_msg = EmailMessage()
|
||||||
|
|
||||||
|
# Add headers
|
||||||
email_msg['Subject'] = self._clean_header_value(msg_file.subject) or _("No Subject")
|
email_msg['Subject'] = self._clean_header_value(msg_file.subject) or _("No Subject")
|
||||||
email_msg['From'] = self._clean_header_value(msg_file.sender)
|
email_msg['From'] = self._clean_header_value(msg_file.sender)
|
||||||
email_msg['To'] = self._clean_header_value(msg_file.to)
|
email_msg['To'] = self._clean_header_value(msg_file.to)
|
||||||
email_msg['Cc'] = self._clean_header_value(msg_file.cc)
|
email_msg['Cc'] = self._clean_header_value(msg_file.cc)
|
||||||
email_msg['Date'] = msg_file.date.strftime('%a, %d %b %Y %H:%M:%S %z') if msg_file.date else ''
|
email_msg['Date'] = msg_file.date.strftime('%a, %d %b %Y %H:%M:%S %z') if msg_file.date else formatdate(localtime=True)
|
||||||
email_msg['References'] = self._clean_header_value(msg_file.header.get('References', ''))
|
|
||||||
email_msg['In-Reply-To'] = self._clean_header_value(msg_file.header.get('In-Reply-To', ''))
|
|
||||||
email_msg['Message-ID'] = self._clean_header_value(msg_file.header.get('Message-Id', ''))
|
|
||||||
|
|
||||||
# Add X-Headers to force message association
|
# Add original MSG headers if present
|
||||||
if self.res_model and self.res_id:
|
for header in ['Message-ID', 'In-Reply-To', 'References']:
|
||||||
email_msg['X-Odoo-Objects'] = f'{self.res_model}-{self.res_id}'
|
if header.lower() in msg_file.header:
|
||||||
|
email_msg[header] = self._clean_header_value(msg_file.header[header.lower()])
|
||||||
|
|
||||||
# Set the body
|
# Set the body
|
||||||
if msg_file.body:
|
if msg_file.body:
|
||||||
_logger.info('Processing message body')
|
_logger.info('Processing message body')
|
||||||
# Convert [cid:xxx] to proper HTML img tags
|
|
||||||
body = msg_file.body
|
body = msg_file.body
|
||||||
|
# Convert [cid:xxx] to proper HTML img tags if needed
|
||||||
cid_pattern = r'\[cid:([^\]]+)\]'
|
cid_pattern = r'\[cid:([^\]]+)\]'
|
||||||
body = re.sub(cid_pattern, r'<img src="cid:\1">', body)
|
body = re.sub(cid_pattern, r'<img src="cid:\1">', body)
|
||||||
# Nettoyer le HTML si nécessaire
|
# Clean HTML if needed
|
||||||
if '<html' in body.lower():
|
if '<html' in body.lower():
|
||||||
body = html_sanitize(body)
|
body = html_sanitize(body)
|
||||||
email_msg.set_content(body, subtype='html')
|
email_msg.set_content(body, subtype='html')
|
||||||
_logger.debug('Message body length: %d characters', len(body))
|
|
||||||
else:
|
else:
|
||||||
_logger.warning('No message body found')
|
_logger.warning('No message body found')
|
||||||
email_msg.set_content('', subtype='html')
|
email_msg.set_content('', subtype='html')
|
||||||
|
|
||||||
# Add attachments
|
# Add attachments
|
||||||
attachment_mapping = {}
|
|
||||||
attachment_ids = []
|
|
||||||
_logger.info('Processing %d attachments', len(msg_file.attachments))
|
_logger.info('Processing %d attachments', len(msg_file.attachments))
|
||||||
for idx, attachment in enumerate(msg_file.attachments, 1):
|
for attachment in msg_file.attachments:
|
||||||
if not hasattr(attachment, 'data') or not attachment.data:
|
if not hasattr(attachment, 'data') or not attachment.data:
|
||||||
_logger.warning('Attachment %d has no data, skipping', idx)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
filename = attachment.getFilename()
|
||||||
|
except AttributeError:
|
||||||
|
filename = 'unknown.bin'
|
||||||
|
_logger.warning('Could not get filename for attachment, using default: %s', filename)
|
||||||
|
|
||||||
maintype, subtype = (attachment.mimetype or 'application/octet-stream').split('/', 1)
|
maintype, subtype = (attachment.mimetype or 'application/octet-stream').split('/', 1)
|
||||||
|
|
||||||
headers = {}
|
headers = {}
|
||||||
|
|
||||||
filename = None
|
|
||||||
if hasattr(attachment, 'filename'):
|
|
||||||
filename = attachment.filename
|
|
||||||
elif hasattr(attachment, 'longFilename'):
|
|
||||||
filename = attachment.longFilename
|
|
||||||
elif hasattr(attachment, 'shortFilename'):
|
|
||||||
filename = attachment.shortFilename
|
|
||||||
|
|
||||||
_logger.info('Processing attachment %d: %s (%s/%s)',
|
|
||||||
idx, filename or 'unknown.bin', maintype, subtype)
|
|
||||||
|
|
||||||
if hasattr(attachment, 'content_id') and attachment.content_id:
|
if hasattr(attachment, 'content_id') and attachment.content_id:
|
||||||
# Ensure Content-ID is properly formatted with <>
|
|
||||||
cid = attachment.content_id.strip('<>')
|
cid = attachment.content_id.strip('<>')
|
||||||
headers['Content-ID'] = f'<{cid}>'
|
headers['Content-ID'] = f'<{cid}>'
|
||||||
|
|
||||||
# Create Odoo attachment for all attachments, not just those with CID
|
|
||||||
try:
|
|
||||||
odoo_attachment = self.env['ir.attachment'].create({
|
|
||||||
'name': filename or 'unknown.bin',
|
|
||||||
'datas': base64.b64encode(attachment.data),
|
|
||||||
'mimetype': attachment.mimetype or 'application/octet-stream',
|
|
||||||
'res_model': self.res_model,
|
|
||||||
'res_id': self.res_id,
|
|
||||||
})
|
|
||||||
_logger.info('Created Odoo attachment: %s (ID: %s)',
|
|
||||||
odoo_attachment.name, odoo_attachment.id)
|
|
||||||
|
|
||||||
attachment_ids.append(odoo_attachment.id)
|
|
||||||
if headers.get('Content-ID'):
|
|
||||||
attachment_mapping[cid] = odoo_attachment.id
|
|
||||||
except Exception as e:
|
|
||||||
_logger.error('Failed to create attachment %s: %s', filename, str(e))
|
|
||||||
|
|
||||||
email_msg.add_attachment(
|
email_msg.add_attachment(
|
||||||
attachment.data,
|
attachment.data,
|
||||||
maintype=maintype,
|
maintype=maintype,
|
||||||
subtype=subtype,
|
subtype=subtype,
|
||||||
filename=filename or 'unknown.bin',
|
filename=filename,
|
||||||
headers=headers
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -168,7 +130,7 @@ class IrAttachment(models.Model):
|
||||||
thread_model = self.env[self.res_model] if self.res_model else self.env['mail.thread']
|
thread_model = self.env[self.res_model] if self.res_model else self.env['mail.thread']
|
||||||
_logger.info('Using thread model: %s', thread_model._name)
|
_logger.info('Using thread model: %s', thread_model._name)
|
||||||
|
|
||||||
# Forcer le contexte pour la création du message
|
# Set context for message creation
|
||||||
context = {
|
context = {
|
||||||
'default_model': self.res_model,
|
'default_model': self.res_model,
|
||||||
'default_res_id': self.res_id,
|
'default_res_id': self.res_id,
|
||||||
|
|
@ -178,93 +140,30 @@ class IrAttachment(models.Model):
|
||||||
'mail_create_force_model': self.res_model,
|
'mail_create_force_model': self.res_model,
|
||||||
'mail_thread_quote': False,
|
'mail_thread_quote': False,
|
||||||
}
|
}
|
||||||
_logger.info('Setting context for message creation: %s', context)
|
|
||||||
thread_model = thread_model.with_context(**context)
|
|
||||||
|
|
||||||
# Créer directement le message si nous avons un modèle et un ID
|
# Process the email using Odoo's standard message_process
|
||||||
if self.res_model and self.res_id:
|
thread_id = thread_model.with_context(**context).message_process(
|
||||||
_logger.info('Creating message directly for model %s with ID %s',
|
model=self.res_model,
|
||||||
self.res_model, self.res_id)
|
message=email_msg.as_bytes(),
|
||||||
# Trouver l'auteur du message
|
custom_values={
|
||||||
author_id = False
|
'res_id': self.res_id,
|
||||||
if msg_file.sender:
|
'model': self.res_model,
|
||||||
email_normalized = email_normalize(msg_file.sender)
|
'msg_attachment_id': self.id,
|
||||||
_logger.info('Looking for partner with email: %s', email_normalized)
|
},
|
||||||
partner = self.env['res.partner'].sudo().search([
|
thread_id=self.res_id
|
||||||
('email_normalized', '=', email_normalized)
|
)
|
||||||
], limit=1)
|
|
||||||
if partner:
|
|
||||||
author_id = partner.id
|
|
||||||
_logger.info('Found partner: %s (ID: %s)', partner.name, partner.id)
|
|
||||||
else:
|
|
||||||
_logger.info('No partner found for email %s', email_normalized)
|
|
||||||
|
|
||||||
# Créer le message directement
|
|
||||||
try:
|
|
||||||
vals = {
|
|
||||||
'subject': msg_file.subject or _("No Subject"),
|
|
||||||
'body': body if msg_file.body else '',
|
|
||||||
'email_from': msg_file.sender,
|
|
||||||
'author_id': author_id,
|
|
||||||
'message_type': 'email',
|
|
||||||
'model': self.res_model,
|
|
||||||
'res_id': self.res_id,
|
|
||||||
'attachment_ids': [(6, 0, attachment_ids)],
|
|
||||||
}
|
|
||||||
_logger.info('Creating mail.message with values: %s', vals)
|
|
||||||
message = self.env['mail.message'].create(vals)
|
|
||||||
_logger.info('Created message successfully: ID %s', message.id)
|
|
||||||
|
|
||||||
# Marquer le fichier MSG comme traité
|
|
||||||
self.write({
|
|
||||||
'description': _('Processed as email on %s') % fields.Datetime.now(),
|
|
||||||
'msg_processed': True,
|
|
||||||
'mail_message_id': message.id,
|
|
||||||
})
|
|
||||||
_logger.info('MSG file marked as processed')
|
|
||||||
|
|
||||||
return message.id
|
|
||||||
except Exception as e:
|
|
||||||
_logger.error('Failed to create message: %s', str(e), exc_info=True)
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
_logger.info('No model/ID available, falling back to message_process')
|
|
||||||
# Si nous n'avons pas de modèle/ID, utiliser message_process
|
|
||||||
thread_id = thread_model.message_process(
|
|
||||||
model=self.res_model,
|
|
||||||
message=email_msg.as_bytes(),
|
|
||||||
custom_values={
|
|
||||||
'res_id': self.res_id,
|
|
||||||
'model': self.res_model,
|
|
||||||
'msg_attachment_id': self.id,
|
|
||||||
},
|
|
||||||
thread_id=self.res_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if thread_id:
|
|
||||||
_logger.info('Message processed successfully, thread_id: %s', thread_id)
|
|
||||||
# Trouver le message créé
|
|
||||||
message = self.env['mail.message'].search([
|
|
||||||
('model', '=', self.res_model),
|
|
||||||
('res_id', '=', thread_id)
|
|
||||||
], order='id desc', limit=1)
|
|
||||||
|
|
||||||
if message:
|
|
||||||
_logger.info('Found created message: ID %s', message.id)
|
|
||||||
else:
|
|
||||||
_logger.warning('No message found after processing')
|
|
||||||
|
|
||||||
# Marquer le fichier MSG comme traité
|
|
||||||
self.write({
|
|
||||||
'description': _('Processed as email on %s') % fields.Datetime.now(),
|
|
||||||
'msg_processed': True,
|
|
||||||
'mail_message_id': message.id if message else False,
|
|
||||||
})
|
|
||||||
_logger.info('MSG file marked as processed')
|
|
||||||
else:
|
|
||||||
_logger.error('message_process failed to create thread_id')
|
|
||||||
|
|
||||||
|
if thread_id:
|
||||||
|
_logger.info('Message processed successfully, thread_id: %s', thread_id)
|
||||||
|
# Mark MSG as processed
|
||||||
|
self.write({
|
||||||
|
'description': _('Processed as email on %s') % fields.Datetime.now(),
|
||||||
|
'msg_processed': True,
|
||||||
|
})
|
||||||
return thread_id
|
return thread_id
|
||||||
|
else:
|
||||||
|
_logger.error('message_process failed to create thread_id')
|
||||||
|
return False
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.error('Error processing MSG file %s: %s', self.name, str(e), exc_info=True)
|
_logger.error('Error processing MSG file %s: %s', self.name, str(e), exc_info=True)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue