[MERGE][IMP] microsoft_outlook, fetchmail_outlook: improve usability, lessen module complexity
Purpose
=======
Improve the usability of the outlook modules. Lessen module complexity.
Specifications
==============
Remove the checkbox "Use Outlook" and instead use the
smtp_authentication and the server_type, to be consistent with Gmail.
Hide the password field for Outlook / Gmail mail servers.
Add constraints on the outgoing mail server to force the user to use
the right configuration (e.g. the from_filter, so the sending do not
fail).
Merge fetchmail_{google/microsoft} into google_gmail / microsoft_outlook?
Most of the time, both module will be installed at the same time, or
none. For that reason, we want to merge both modules, for both
providers, to lessen complexity.
Task-2811567
closes odoo/odoo#88215
Related: odoo/upgrade#3419
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -43,10 +43,11 @@ class FetchmailServer(models.Model):
|
||||
server = fields.Char(string='Server Name', readonly=True, help="Hostname or IP of the mail server", states={'draft': [('readonly', False)]})
|
||||
port = fields.Integer(readonly=True, states={'draft': [('readonly', False)]})
|
||||
server_type = fields.Selection([
|
||||
('pop', 'POP Server'),
|
||||
('imap', 'IMAP Server'),
|
||||
('pop', 'POP Server'),
|
||||
('local', 'Local Server'),
|
||||
], string='Server Type', index=True, required=True, default='pop')
|
||||
server_type_info = fields.Text('Server Type Info', compute='_compute_server_type_info')
|
||||
is_ssl = fields.Boolean('SSL/TLS', help="Connections are encrypted with SSL/TLS through a dedicated port (default: IMAPS=993, POP3S=995)")
|
||||
attach = fields.Boolean('Keep Attachments', help="Whether attachments should be downloaded. "
|
||||
"If not enabled, incoming emails will be stripped of any attachments before being processed", default=True)
|
||||
@@ -64,6 +65,14 @@ class FetchmailServer(models.Model):
|
||||
configuration = fields.Text('Configuration', readonly=True)
|
||||
script = fields.Char(readonly=True, default='/mail/static/scripts/odoo-mailgate.py')
|
||||
|
||||
@api.depends('server_type')
|
||||
def _compute_server_type_info(self):
|
||||
for server in self:
|
||||
if server.server_type == 'local':
|
||||
server.server_type_info = _('Use a local script to fetch your emails and create new records.')
|
||||
else:
|
||||
server.server_type_info = False
|
||||
|
||||
@api.onchange('server_type', 'is_ssl', 'object_id')
|
||||
def onchange_server_type(self):
|
||||
self.port = 0
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<field name="name">fetchmail.server.list</field>
|
||||
<field name="model">fetchmail.server</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree decoration-info="state == 'draft'" string="POP/IMAP Servers">
|
||||
<tree string="POP/IMAP Servers">
|
||||
<field name="name"/>
|
||||
<field name="server_type"/>
|
||||
<field name="is_ssl"/>
|
||||
<field name="object_id"/>
|
||||
<field name="user"/>
|
||||
<field name="date"/>
|
||||
<field name="message_ids" string="Email Count"/>
|
||||
<field name="state"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state == 'draft'"
|
||||
decoration-success="state == 'done'"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
@@ -29,10 +29,20 @@
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="server_type" widget="radio"/>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="server_type" widget="radio" attrs="{'readonly': [('state', '=', 'done')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date" attrs="{'invisible': [('date', '=', False)]}"/>
|
||||
<div class="text-muted font-italic" colspan="8" role="alert"
|
||||
attrs="{'invisible': [('server_type_info', '=', False)]}">
|
||||
<field name="server_type_info"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Server & Login" name="server_login_details">
|
||||
@@ -47,7 +57,8 @@
|
||||
</group>
|
||||
<group attrs="{'invisible' : [('server_type', '=', 'local')]}" string="Login Information">
|
||||
<field name="user" attrs="{'required' : [('server_type', '!=', 'local')]}"/>
|
||||
<field name="password" password="True" attrs="{'required' : [('server_type', '!=', 'local')]}"/>
|
||||
<field name="password" password="True"
|
||||
attrs="{'required' : [('server_type', 'in', ('imap', 'pop'))], 'invisible' : [('server_type', 'not in', ('imap', 'pop'))]}"/>
|
||||
</group>
|
||||
<group string="Actions to Perform on Incoming Mails">
|
||||
<field name="object_id"/>
|
||||
@@ -63,7 +74,7 @@
|
||||
<field name="priority"/>
|
||||
<field name="attach"/>
|
||||
<field name="original"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
<field name="active" invisible="1"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
@@ -78,6 +89,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Incoming Mail Servers">
|
||||
<field name="name" string="Incoming Mail Server"/>
|
||||
<field name="user"/>
|
||||
<filter string="IMAP" name="imap" domain="[('server_type', '=', 'imap')]" help="Server type IMAP."/>
|
||||
<filter string="POP" name="pop" domain="[('server_type', '=', 'pop')]" help="Server type POP."/>
|
||||
<separator/>
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -1,16 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
"name": "Fetchmail Gmail",
|
||||
"version": "1.1",
|
||||
"category": "Hidden",
|
||||
"description": "Google authentication for incoming mail server",
|
||||
"depends": [
|
||||
"google_gmail",
|
||||
"fetchmail",
|
||||
],
|
||||
"data": ["views/fetchmail_server_views.xml"],
|
||||
"auto_install": True,
|
||||
"license": "LGPL-3",
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * fetchmail_gmail
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~15.2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-11 14:34+0000\n"
|
||||
"PO-Revision-Date: 2022-02-11 14:34+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_gmail.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<i class=\"fa fa-arrow-right\"/>\n"
|
||||
" Connect your Gmail account"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_gmail.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<i class=\"fa fa-cog\"/>\n"
|
||||
" Edit Settings"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_gmail.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<span attrs=\"{'invisible': ['|', ('server_type', '!=', 'gmail'), ('google_gmail_refresh_token', '=', False)]}\" class=\"badge badge-success\">\n"
|
||||
" Gmail Token Valid\n"
|
||||
" </span>"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__google_gmail_access_token
|
||||
msgid "Access Token"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__google_gmail_access_token_expiration
|
||||
msgid "Access Token Expiration Timestamp"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__google_gmail_authorization_code
|
||||
msgid "Authorization Code"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields.selection,name:fetchmail_gmail.selection__fetchmail_server__server_type__gmail
|
||||
msgid "Gmail OAuth Authentication"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model,name:fetchmail_gmail.model_fetchmail_server
|
||||
msgid "Incoming Mail Server"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__google_gmail_refresh_token
|
||||
msgid "Refresh Token"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__server_type
|
||||
msgid "Server Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_gmail.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"Setup your Gmail API credentials in the general settings to link a Gmail "
|
||||
"account."
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,help:fetchmail_gmail.field_fetchmail_server__google_gmail_uri
|
||||
msgid "The URL to generate the authorization code from Google"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_gmail
|
||||
#: model:ir.model.fields,field_description:fetchmail_gmail.field_fetchmail_server__google_gmail_uri
|
||||
msgid "URI"
|
||||
msgstr ""
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import fetchmail_server
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
"name": "Fetchmail Outlook",
|
||||
"version": "1.0",
|
||||
"category": "Hidden",
|
||||
"description": "OAuth authentication for incoming Outlook mail server",
|
||||
"depends": [
|
||||
"microsoft_outlook",
|
||||
"fetchmail",
|
||||
],
|
||||
"data": [
|
||||
"views/fetchmail_server_views.xml",
|
||||
],
|
||||
"auto_install": True,
|
||||
"license": "LGPL-3",
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * fetchmail_outlook
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~15.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-06-09 14:05+0000\n"
|
||||
"PO-Revision-Date: 2022-06-09 14:05+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_outlook.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<i class=\"fa fa-arrow-right\"/>\n"
|
||||
" Connect your Outlook account"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_outlook.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<i class=\"fa fa-cog\"/>\n"
|
||||
" Edit Settings"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_outlook.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"<span attrs=\"{'invisible': ['|', ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '=', False)]}\" class=\"badge badge-success\">\n"
|
||||
" Outlook Token Valid\n"
|
||||
" </span>"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__microsoft_outlook_uri
|
||||
msgid "Authentication URI"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model,name:fetchmail_outlook.model_fetchmail_server
|
||||
msgid "Incoming Mail Server"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__is_microsoft_outlook_configured
|
||||
msgid "Is Outlook Credential Configured"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_outlook.fetchmail_server_view_form
|
||||
msgid "Outlook"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__microsoft_outlook_access_token
|
||||
msgid "Outlook Access Token"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__microsoft_outlook_access_token_expiration
|
||||
msgid "Outlook Access Token Expiration Timestamp"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__use_microsoft_outlook_service
|
||||
msgid "Outlook Authentication"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,field_description:fetchmail_outlook.field_fetchmail_server__microsoft_outlook_refresh_token
|
||||
msgid "Outlook Refresh Token"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: code:addons/fetchmail_outlook/models/fetchmail_server.py:0
|
||||
#, python-format
|
||||
msgid "Outlook mail server %r only supports IMAP server type."
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: code:addons/fetchmail_outlook/models/fetchmail_server.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Please leave the password field empty for Outlook mail server %r. The OAuth "
|
||||
"process does not require it"
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: code:addons/fetchmail_outlook/models/fetchmail_server.py:0
|
||||
#, python-format
|
||||
msgid "SSL is required ."
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model_terms:ir.ui.view,arch_db:fetchmail_outlook.fetchmail_server_view_form
|
||||
msgid ""
|
||||
"Setup your Outlook API credentials in the general settings to link a Outlook"
|
||||
" account."
|
||||
msgstr ""
|
||||
|
||||
#. module: fetchmail_outlook
|
||||
#: model:ir.model.fields,help:fetchmail_outlook.field_fetchmail_server__microsoft_outlook_uri
|
||||
msgid "The URL to generate the authorization code from Outlook"
|
||||
msgstr ""
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import fetchmail_server
|
||||
@@ -1,57 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class FetchmailServer(models.Model):
|
||||
"""Add the Outlook OAuth authentication on the incoming mail servers."""
|
||||
|
||||
_name = 'fetchmail.server'
|
||||
_inherit = ['fetchmail.server', 'microsoft.outlook.mixin']
|
||||
|
||||
_OUTLOOK_SCOPE = 'https://outlook.office.com/IMAP.AccessAsUser.All'
|
||||
|
||||
@api.constrains('use_microsoft_outlook_service', 'server_type', 'password', 'is_ssl')
|
||||
def _check_use_microsoft_outlook_service(self):
|
||||
for server in self:
|
||||
if not server.use_microsoft_outlook_service:
|
||||
continue
|
||||
|
||||
if server.server_type != 'imap':
|
||||
raise UserError(_('Outlook mail server %r only supports IMAP server type.', server.name))
|
||||
|
||||
if server.password:
|
||||
raise UserError(_(
|
||||
'Please leave the password field empty for Outlook mail server %r. '
|
||||
'The OAuth process does not require it', server.name))
|
||||
|
||||
if not server.is_ssl:
|
||||
raise UserError(_('SSL is required .', server.name))
|
||||
|
||||
@api.onchange('use_microsoft_outlook_service')
|
||||
def _onchange_use_microsoft_outlook_service(self):
|
||||
"""Set the default configuration for a IMAP Outlook server."""
|
||||
if self.use_microsoft_outlook_service:
|
||||
self.server = 'imap.outlook.com'
|
||||
self.server_type = 'imap'
|
||||
self.is_ssl = True
|
||||
self.port = 993
|
||||
else:
|
||||
self.microsoft_outlook_refresh_token = False
|
||||
self.microsoft_outlook_access_token = False
|
||||
self.microsoft_outlook_access_token_expiration = False
|
||||
|
||||
def _imap_login(self, connection):
|
||||
"""Authenticate the IMAP connection.
|
||||
|
||||
If the mail server is Outlook, we use the OAuth2 authentication protocol.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.use_microsoft_outlook_service:
|
||||
auth_string = self._generate_outlook_oauth2_string(self.user)
|
||||
connection.authenticate('XOAUTH2', lambda x: auth_string)
|
||||
connection.select('INBOX')
|
||||
else:
|
||||
super()._imap_login(connection)
|
||||
@@ -131,7 +131,7 @@ class GoogleService(models.AbstractModel):
|
||||
raise UserError(_('Google %s is not yet configured.', service.title()))
|
||||
|
||||
if not refresh_token:
|
||||
raise UserError(_('The refresh token for authentication is not set.'))
|
||||
raise UserError(_('Your Google account is not connected.'))
|
||||
|
||||
try:
|
||||
result = requests.post(
|
||||
|
||||
@@ -3,17 +3,23 @@
|
||||
|
||||
{
|
||||
"name": "Google Gmail",
|
||||
"version": "1.1",
|
||||
"version": "1.2",
|
||||
"category": "Hidden",
|
||||
"description": "Gmail support for incoming / outgoing mail servers",
|
||||
"depends": [
|
||||
"fetchmail",
|
||||
"mail",
|
||||
"google_account",
|
||||
],
|
||||
"data": [
|
||||
"views/fetchmail_server_views.xml",
|
||||
"views/ir_mail_server_views.xml",
|
||||
"views/res_config_settings_views.xml",
|
||||
],
|
||||
"auto_install": True,
|
||||
"license": "LGPL-3",
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"google_gmail/static/src/scss/google_gmail.scss",
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import google_gmail_mixin
|
||||
|
||||
from . import fetchmail_server
|
||||
from . import ir_mail_server
|
||||
from . import res_config_settings
|
||||
|
||||
+9
-1
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class FetchmailServer(models.Model):
|
||||
@@ -10,6 +10,14 @@ class FetchmailServer(models.Model):
|
||||
|
||||
server_type = fields.Selection(selection_add=[('gmail', 'Gmail OAuth Authentication')], ondelete={'gmail': 'set default'})
|
||||
|
||||
def _compute_server_type_info(self):
|
||||
gmail_servers = self.filtered(lambda server: server.server_type == 'gmail')
|
||||
gmail_servers.server_type_info = _(
|
||||
'Connect your Gmail account with the OAuth Authentication process. \n'
|
||||
'You will be redirected to the Gmail login page where you will '
|
||||
'need to accept the permission.')
|
||||
super(FetchmailServer, self - gmail_servers)._compute_server_type_info()
|
||||
|
||||
@api.onchange('server_type', 'is_ssl', 'object_id')
|
||||
def onchange_server_type(self):
|
||||
"""Set the default configuration for a IMAP Gmail server."""
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
import base64
|
||||
|
||||
from odoo import fields, models, api
|
||||
from odoo import _, fields, models, api
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class IrMailServer(models.Model):
|
||||
@@ -16,6 +17,14 @@ class IrMailServer(models.Model):
|
||||
selection_add=[('gmail', 'Gmail OAuth Authentication')],
|
||||
ondelete={'gmail': 'set default'})
|
||||
|
||||
def _compute_smtp_authentication_info(self):
|
||||
gmail_servers = self.filtered(lambda server: server.smtp_authentication == 'gmail')
|
||||
gmail_servers.smtp_authentication_info = _(
|
||||
'Connect your Gmail account with the OAuth Authentication process. \n'
|
||||
'By default, only a user with a matching email address will be able to use this server. '
|
||||
'To extend its use, you should set a "mail.default.from" system parameter.')
|
||||
super(IrMailServer, self - gmail_servers)._compute_smtp_authentication_info()
|
||||
|
||||
@api.onchange('smtp_encryption')
|
||||
def _onchange_encryption(self):
|
||||
"""Do not change the SMTP configuration if it's a Gmail server
|
||||
@@ -24,7 +33,7 @@ class IrMailServer(models.Model):
|
||||
super(IrMailServer, self)._onchange_encryption()
|
||||
|
||||
@api.onchange('smtp_authentication')
|
||||
def _onchange_smtp_authentication(self):
|
||||
def _onchange_smtp_authentication_gmail(self):
|
||||
if self.smtp_authentication == 'gmail':
|
||||
self.smtp_host = 'smtp.gmail.com'
|
||||
self.smtp_encryption = 'starttls'
|
||||
@@ -35,6 +44,31 @@ class IrMailServer(models.Model):
|
||||
self.google_gmail_access_token = False
|
||||
self.google_gmail_access_token_expiration = False
|
||||
|
||||
@api.onchange('smtp_user', 'smtp_authentication')
|
||||
def _on_change_smtp_user_gmail(self):
|
||||
"""The Gmail mail servers can only be used for the user personal email address."""
|
||||
if self.smtp_authentication == 'gmail':
|
||||
self.from_filter = self.smtp_user
|
||||
|
||||
@api.constrains('smtp_authentication', 'smtp_pass', 'smtp_encryption', 'from_filter', 'smtp_user')
|
||||
def _check_use_google_gmail_service(self):
|
||||
gmail_servers = self.filtered(lambda server: server.smtp_authentication == 'gmail')
|
||||
for server in gmail_servers:
|
||||
if server.smtp_pass:
|
||||
raise UserError(_(
|
||||
'Please leave the password field empty for Gmail mail server %r. '
|
||||
'The OAuth process does not require it', server.name))
|
||||
|
||||
if server.smtp_encryption != 'starttls':
|
||||
raise UserError(_(
|
||||
'Incorrect Connection Security for Gmail mail server %r. '
|
||||
'Please set it to "TLS (STARTTLS)".', server.name))
|
||||
|
||||
if server.from_filter != server.smtp_user:
|
||||
raise UserError(_(
|
||||
'This server %r can only be used for your personal email address. '
|
||||
'Please fill the "from_filter" field with %r.', server.name, server.smtp_user))
|
||||
|
||||
def _smtp_login(self, connection, smtp_user, smtp_password):
|
||||
if len(self) == 1 and self.smtp_authentication == 'gmail':
|
||||
auth_string = self._generate_oauth2_string(smtp_user, self.google_gmail_refresh_token)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" ?><svg height="48px" viewBox="0 0 48 48" width="48px" xmlns="http://www.w3.org/2000/svg"><path d="M45,16.2l-5,2.75l-5,4.75L35,40h7c1.657,0,3-1.343,3-3V16.2z" fill="#4caf50"/><path d="M3,16.2l3.614,1.71L13,23.7V40H6c-1.657,0-3-1.343-3-3V16.2z" fill="#1e88e5"/><polygon fill="#e53935" points="35,11.2 24,19.45 13,11.2 12,17 13,23.7 24,31.95 35,23.7 36,17"/><path d="M3,12.298V16.2l10,7.5V11.2L9.876,8.859C9.132,8.301,8.228,8,7.298,8h0C4.924,8,3,9.924,3,12.298z" fill="#c62828"/><path d="M45,12.298V16.2l-10,7.5V11.2l3.124-2.341C38.868,8.301,39.772,8,40.702,8h0 C43.076,8,45,9.924,45,12.298z" fill="#fbc02d"/></svg>
|
||||
|
After Width: | Height: | Size: 632 B |
@@ -0,0 +1,4 @@
|
||||
span.o_field_char[name="google_gmail_authorization_code"] {
|
||||
max-width: 150px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
+8
-12
@@ -9,8 +9,8 @@
|
||||
<field name="user" position="after">
|
||||
<field name="google_gmail_uri" invisible="1"/>
|
||||
<field name="google_gmail_refresh_token" invisible="1"/>
|
||||
<div></div>
|
||||
<div attrs="{'invisible': [('server_type', '!=', 'gmail')]}">
|
||||
<div attrs="{'invisible': [('server_type', '!=', 'gmail')]}"
|
||||
class="d-flex flex-row align-items-center" colspan="8">
|
||||
<span attrs="{'invisible': ['|', ('server_type', '!=', 'gmail'), ('google_gmail_refresh_token', '=', False)]}"
|
||||
class="badge text-bg-success">
|
||||
Gmail Token Valid
|
||||
@@ -22,22 +22,18 @@
|
||||
Connect your Gmail account
|
||||
</button>
|
||||
<button type="object"
|
||||
name="open_google_gmail_uri" class="btn-link px-0"
|
||||
name="open_google_gmail_uri" class="btn-link px-0 ml-2"
|
||||
attrs="{'invisible': ['|', '|', ('google_gmail_uri', '=', False), ('server_type', '!=', 'gmail'), ('google_gmail_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog"/>
|
||||
Edit Settings
|
||||
<i class="fa fa-cog" title="Edit Settings"/>
|
||||
</button>
|
||||
<div class="alert alert-warning" role="alert"
|
||||
<button class="alert alert-warning d-block mt-2 text-left"
|
||||
icon="fa-arrow-right" type="action" role="alert"
|
||||
name="%(base.res_config_setting_act_window)d"
|
||||
attrs="{'invisible': ['|', ('server_type', '!=', 'gmail'), ('google_gmail_uri', '!=', False)]}">
|
||||
Setup your Gmail API credentials in the general settings to link a Gmail account.
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
<field name="password" position="attributes">
|
||||
<attribute name="attrs">
|
||||
{'required' : [('server_type', '!=', 'local'), ('server_type', '!=', 'gmail'), ('password', '!=', False)], 'invisible' : [('server_type', '=', 'gmail')]}
|
||||
</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -8,8 +8,8 @@
|
||||
<field name="smtp_user" position="after">
|
||||
<field name="google_gmail_uri" invisible="1"/>
|
||||
<field name="google_gmail_refresh_token" invisible="1"/>
|
||||
<div></div>
|
||||
<div attrs="{'invisible': [('smtp_authentication', '!=', 'gmail')]}">
|
||||
<div attrs="{'invisible': [('smtp_authentication', '!=', 'gmail')]}"
|
||||
class="d-flex flex-row align-items-center" colspan="8">
|
||||
<span attrs="{'invisible': ['|', ('smtp_authentication', '!=', 'gmail'), ('google_gmail_refresh_token', '=', False)]}"
|
||||
class="badge text-bg-success">
|
||||
Gmail Token Valid
|
||||
@@ -21,22 +21,23 @@
|
||||
Connect your Gmail account
|
||||
</button>
|
||||
<button type="object"
|
||||
name="open_google_gmail_uri" class="btn-link px-0"
|
||||
name="open_google_gmail_uri" class="btn-link px-0 ml-2"
|
||||
attrs="{'invisible': ['|', '|', ('google_gmail_uri', '=', False), ('smtp_authentication', '!=', 'gmail'), ('google_gmail_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog"/>
|
||||
Edit Settings
|
||||
<i class="fa fa-cog" title="Edit Settings"/>
|
||||
</button>
|
||||
<div class="alert alert-warning" role="alert"
|
||||
<button class="alert alert-warning d-block mt-2 text-left"
|
||||
icon="fa-arrow-right" type="action" role="alert"
|
||||
name="%(base.res_config_setting_act_window)d"
|
||||
attrs="{'invisible': ['|', ('smtp_authentication', '!=', 'gmail'), ('google_gmail_uri', '!=', False)]}">
|
||||
Setup your Gmail API credentials in the general settings to link a Gmail account.
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
<field name="smtp_user" position="attributes">
|
||||
<attribute name="attrs">{'invisible' : [('smtp_authentication', '!=', 'login'), ('smtp_authentication', '!=', 'gmail')]}</attribute>
|
||||
</field>
|
||||
<field name="smtp_pass" position="attributes">
|
||||
<attribute name="attrs">{'invisible' : [('smtp_authentication', '=', 'gmail')]}</attribute>
|
||||
<field name="smtp_authentication_info" position="after">
|
||||
<a href="https://www.odoo.com/documentation/15.0/applications/general/email_communication/email_servers.html?highlight=outgoing email server#use-a-default-from-email-address"
|
||||
attrs="{'invisible': [('smtp_authentication', '!=', 'gmail')]}" target="_blank">
|
||||
Read More
|
||||
</a>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -8,12 +8,14 @@
|
||||
<field name="arch" type="xml">
|
||||
<div id="msg_module_google_gmail" position="replace">
|
||||
<div class="row mt16" id="gmail_client_identifier">
|
||||
<label string="Client ID" for="google_gmail_client_identifier" class="col-lg-3 o_light_label"/>
|
||||
<field name="google_gmail_client_identifier" class="ms-2"/>
|
||||
<label string="ID" for="google_gmail_client_identifier" class="col-lg-3 o_light_label"/>
|
||||
<field name="google_gmail_client_identifier" class="ms-2"
|
||||
placeholder="ID of your Google app"/>
|
||||
</div>
|
||||
<div class="row mt16" id="gmail_client_secret">
|
||||
<label string="Client Secret" for="google_gmail_client_secret" class="col-lg-3 o_light_label"/>
|
||||
<field name="google_gmail_client_secret" class="ms-2"/>
|
||||
<label string="Secret" for="google_gmail_client_secret" class="col-lg-3 o_light_label"/>
|
||||
<field name="google_gmail_client_secret" class="ms-2"
|
||||
placeholder="Secret of your Google app"/>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
|
||||
@@ -16,6 +16,7 @@ class ResConfigSettings(models.TransientModel):
|
||||
'Alias Domain', config_parameter='mail.catchall.domain',
|
||||
help="If you have setup a catch-all email domain redirected to the Odoo server, enter the domain name here.")
|
||||
module_google_gmail = fields.Boolean('Support Gmail Authentication')
|
||||
module_microsoft_outlook = fields.Boolean('Support Outlook Authentication')
|
||||
restrict_template_rendering = fields.Boolean(
|
||||
'Restrict Template Rendering',
|
||||
config_parameter='mail.restrict.template.rendering',
|
||||
|
||||
@@ -36,13 +36,43 @@
|
||||
<div class="text-muted" id="external_email_server_default">
|
||||
Configure your own email servers
|
||||
</div>
|
||||
<div class="content-group" attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<div class="content-group mb-3" attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<div class="mt16" id="mail_alias_domain">
|
||||
<label for="alias_domain" class="o_light_label"/>
|
||||
<span>@</span>
|
||||
<field name="alias_domain" placeholder='e.g. "mycompany.com"'/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 d-flex" attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<field name="module_google_gmail"/>
|
||||
<div>
|
||||
<label string="Gmail Credentials" for="module_google_gmail"/>
|
||||
<a href="https://console.developers.google.com/" title="Get Gmail API credentials" class="o_doc_link" target="_blank"/>
|
||||
<div class="text-muted">
|
||||
Send and receive emails through your Gmail account.
|
||||
</div>
|
||||
<div class="content-group" attrs="{'invisible': [('module_google_gmail','=',False)]}" id="msg_module_google_gmail">
|
||||
<div class="mt16 text-warning"><strong>Save</strong> this page and come back here to set up the feature.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 d-flex" attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<field name="module_microsoft_outlook"/>
|
||||
<div>
|
||||
<label string="Outlook Credentials" for="module_microsoft_outlook"/>
|
||||
<a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app"
|
||||
title="Get Outlook API credentials" class="o_doc_link" target="_blank"/>
|
||||
<div class="text-muted">
|
||||
Send and receive emails through your Outlook account.
|
||||
</div>
|
||||
<div class="content-group" id="msg_module_microsoft_outlook"
|
||||
attrs="{'invisible': [('module_microsoft_outlook','=',False)]}">
|
||||
<div class="mt16 text-warning">
|
||||
<strong>Save</strong> this page and come back here to set up the feature.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
@@ -66,22 +96,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="google_gmail_setting"
|
||||
attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="module_google_gmail"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label string="Gmail Credentials" for="module_google_gmail"/>
|
||||
<a href="https://console.developers.google.com/" title="Get Gmail API credentials" class="o_doc_link" target="_blank"/>
|
||||
<div class="text-muted">
|
||||
Send and receive emails with your Gmail account.
|
||||
</div>
|
||||
<div class="content-group" attrs="{'invisible': [('module_google_gmail','=',False)]}" id="msg_module_google_gmail">
|
||||
<div class="mt16 text-warning"><strong>Save</strong> this page and come back here to set up the feature.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Custom ICE server list</span>
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
|
||||
{
|
||||
"name": "Microsoft Outlook",
|
||||
"version": "1.0",
|
||||
"version": "1.1",
|
||||
"category": "Hidden",
|
||||
"description": "Outlook support for outgoing mail servers",
|
||||
"description": "Outlook support for incoming / outgoing mail servers",
|
||||
"depends": [
|
||||
"fetchmail",
|
||||
"mail",
|
||||
],
|
||||
"data": [
|
||||
"views/fetchmail_server_views.xml",
|
||||
"views/ir_mail_server_views.xml",
|
||||
"views/res_config_settings_views.xml",
|
||||
"views/templates.xml",
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
|
||||
from . import microsoft_outlook_mixin
|
||||
|
||||
from . import fetchmail_server
|
||||
from . import ir_mail_server
|
||||
from . import res_config_settings
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class FetchmailServer(models.Model):
|
||||
"""Add the Outlook OAuth authentication on the incoming mail servers."""
|
||||
|
||||
_name = 'fetchmail.server'
|
||||
_inherit = ['fetchmail.server', 'microsoft.outlook.mixin']
|
||||
|
||||
_OUTLOOK_SCOPE = 'https://outlook.office.com/IMAP.AccessAsUser.All'
|
||||
|
||||
server_type = fields.Selection(selection_add=[('outlook', 'Outlook OAuth Authentication')], ondelete={'outlook': 'set default'})
|
||||
|
||||
def _compute_server_type_info(self):
|
||||
outlook_servers = self.filtered(lambda server: server.server_type == 'outlook')
|
||||
outlook_servers.server_type_info = _(
|
||||
'Connect your personal Outlook account using OAuth. \n'
|
||||
'You will be redirected to the Outlook login page to accept '
|
||||
'the permissions.')
|
||||
super(FetchmailServer, self - outlook_servers)._compute_server_type_info()
|
||||
|
||||
@api.depends('server_type')
|
||||
def _compute_is_microsoft_outlook_configured(self):
|
||||
outlook_servers = self.filtered(lambda server: server.server_type == 'outlook')
|
||||
(self - outlook_servers).is_microsoft_outlook_configured = False
|
||||
super(FetchmailServer, outlook_servers)._compute_is_microsoft_outlook_configured()
|
||||
|
||||
@api.constrains('server_type', 'is_ssl')
|
||||
def _check_use_microsoft_outlook_service(self):
|
||||
for server in self:
|
||||
if server.server_type == 'outlook' and not server.is_ssl:
|
||||
raise UserError(_('SSL is required for the server %r.', server.name))
|
||||
|
||||
@api.onchange('server_type')
|
||||
def onchange_server_type(self):
|
||||
"""Set the default configuration for a IMAP Outlook server."""
|
||||
if self.server_type == 'outlook':
|
||||
self.server = 'imap.outlook.com'
|
||||
self.is_ssl = True
|
||||
self.port = 993
|
||||
else:
|
||||
self.microsoft_outlook_refresh_token = False
|
||||
self.microsoft_outlook_access_token = False
|
||||
self.microsoft_outlook_access_token_expiration = False
|
||||
super(FetchmailServer, self).onchange_server_type()
|
||||
|
||||
def _imap_login(self, connection):
|
||||
"""Authenticate the IMAP connection.
|
||||
|
||||
If the mail server is Outlook, we use the OAuth2 authentication protocol.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.server_type == 'outlook':
|
||||
auth_string = self._generate_outlook_oauth2_string(self.user)
|
||||
connection.authenticate('XOAUTH2', lambda x: auth_string)
|
||||
connection.select('INBOX')
|
||||
else:
|
||||
super()._imap_login(connection)
|
||||
|
||||
def _get_connection_type(self):
|
||||
"""Return which connection must be used for this mail server (IMAP or POP).
|
||||
The Outlook mail server used an IMAP connection.
|
||||
"""
|
||||
self.ensure_one()
|
||||
return 'imap' if self.server_type == 'outlook' else super()._get_connection_type()
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import base64
|
||||
|
||||
from odoo import _, api, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
@@ -15,12 +15,28 @@ class IrMailServer(models.Model):
|
||||
|
||||
_OUTLOOK_SCOPE = 'https://outlook.office.com/SMTP.Send'
|
||||
|
||||
@api.constrains('use_microsoft_outlook_service', 'smtp_pass', 'smtp_encryption')
|
||||
def _check_use_microsoft_outlook_service(self):
|
||||
for server in self:
|
||||
if not server.use_microsoft_outlook_service:
|
||||
continue
|
||||
smtp_authentication = fields.Selection(
|
||||
selection_add=[('outlook', 'Outlook OAuth Authentication')],
|
||||
ondelete={'outlook': 'set default'})
|
||||
|
||||
@api.depends('smtp_authentication')
|
||||
def _compute_is_microsoft_outlook_configured(self):
|
||||
outlook_servers = self.filtered(lambda server: server.smtp_authentication == 'outlook')
|
||||
(self - outlook_servers).is_microsoft_outlook_configured = False
|
||||
super(IrMailServer, outlook_servers)._compute_is_microsoft_outlook_configured()
|
||||
|
||||
def _compute_smtp_authentication_info(self):
|
||||
outlook_servers = self.filtered(lambda server: server.smtp_authentication == 'outlook')
|
||||
outlook_servers.smtp_authentication_info = _(
|
||||
'Connect your Outlook account with the OAuth Authentication process. \n'
|
||||
'By default, only a user with a matching email address will be able to use this server. '
|
||||
'To extend its use, you should set a "mail.default.from" system parameter.')
|
||||
super(IrMailServer, self - outlook_servers)._compute_smtp_authentication_info()
|
||||
|
||||
@api.constrains('smtp_authentication', 'smtp_pass', 'smtp_encryption', 'from_filter', 'smtp_user')
|
||||
def _check_use_microsoft_outlook_service(self):
|
||||
outlook_servers = self.filtered(lambda server: server.smtp_authentication == 'outlook')
|
||||
for server in outlook_servers:
|
||||
if server.smtp_pass:
|
||||
raise UserError(_(
|
||||
'Please leave the password field empty for Outlook mail server %r. '
|
||||
@@ -31,17 +47,22 @@ class IrMailServer(models.Model):
|
||||
'Incorrect Connection Security for Outlook mail server %r. '
|
||||
'Please set it to "TLS (STARTTLS)".', server.name))
|
||||
|
||||
if server.from_filter != server.smtp_user:
|
||||
raise UserError(_(
|
||||
'This server %r can only be used for your personal email address. '
|
||||
'Please fill the "from_filter" field with %r.', server.name, server.smtp_user))
|
||||
|
||||
@api.onchange('smtp_encryption')
|
||||
def _onchange_encryption(self):
|
||||
"""Do not change the SMTP configuration if it's a Outlook server
|
||||
|
||||
(e.g. the port which is already set)"""
|
||||
if not self.use_microsoft_outlook_service:
|
||||
if self.smtp_authentication != 'outlook':
|
||||
super()._onchange_encryption()
|
||||
|
||||
@api.onchange('use_microsoft_outlook_service')
|
||||
def _onchange_use_microsoft_outlook_service(self):
|
||||
if self.use_microsoft_outlook_service:
|
||||
@api.onchange('smtp_authentication')
|
||||
def _onchange_smtp_authentication_outlook(self):
|
||||
if self.smtp_authentication == 'outlook':
|
||||
self.smtp_host = 'smtp.outlook.com'
|
||||
self.smtp_encryption = 'starttls'
|
||||
self.smtp_port = 587
|
||||
@@ -50,11 +71,17 @@ class IrMailServer(models.Model):
|
||||
self.microsoft_outlook_access_token = False
|
||||
self.microsoft_outlook_access_token_expiration = False
|
||||
|
||||
@api.onchange('smtp_user', 'smtp_authentication')
|
||||
def _on_change_smtp_user_outlook(self):
|
||||
"""The Outlook mail servers can only be used for the user personal email address."""
|
||||
if self.smtp_authentication == 'outlook':
|
||||
self.from_filter = self.smtp_user
|
||||
|
||||
def _smtp_login(self, connection, smtp_user, smtp_password):
|
||||
if len(self) == 1 and self.use_microsoft_outlook_service:
|
||||
if len(self) == 1 and self.smtp_authentication == 'outlook':
|
||||
auth_string = self._generate_outlook_oauth2_string(smtp_user)
|
||||
oauth_param = base64.b64encode(auth_string.encode()).decode()
|
||||
connection.ehlo()
|
||||
connection.docmd('AUTH', 'XOAUTH2 %s' % oauth_param)
|
||||
connection.docmd('AUTH', f'XOAUTH2 {oauth_param}')
|
||||
else:
|
||||
super()._smtp_login(connection, smtp_user, smtp_password)
|
||||
|
||||
@@ -23,7 +23,6 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
||||
_OUTLOOK_SCOPE = None
|
||||
_OUTLOOK_ENDPOINT = 'https://login.microsoftonline.com/common/oauth2/v2.0/'
|
||||
|
||||
use_microsoft_outlook_service = fields.Boolean('Outlook Authentication')
|
||||
is_microsoft_outlook_configured = fields.Boolean('Is Outlook Credential Configured',
|
||||
compute='_compute_is_microsoft_outlook_configured')
|
||||
microsoft_outlook_refresh_token = fields.Char(string='Outlook Refresh Token',
|
||||
@@ -35,25 +34,25 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
||||
microsoft_outlook_uri = fields.Char(compute='_compute_outlook_uri', string='Authentication URI',
|
||||
help='The URL to generate the authorization code from Outlook', groups='base.group_system')
|
||||
|
||||
@api.depends('use_microsoft_outlook_service')
|
||||
def _compute_is_microsoft_outlook_configured(self):
|
||||
Config = self.env['ir.config_parameter'].sudo()
|
||||
microsoft_outlook_client_id = Config.get_param('microsoft_outlook_client_id')
|
||||
microsoft_outlook_client_secret = Config.get_param('microsoft_outlook_client_secret')
|
||||
self.is_microsoft_outlook_configured = microsoft_outlook_client_id and microsoft_outlook_client_secret
|
||||
|
||||
@api.depends('use_microsoft_outlook_service')
|
||||
@api.depends('is_microsoft_outlook_configured')
|
||||
def _compute_outlook_uri(self):
|
||||
Config = self.env['ir.config_parameter'].sudo()
|
||||
base_url = self.get_base_url()
|
||||
microsoft_outlook_client_id = Config.get_param('microsoft_outlook_client_id')
|
||||
OUTLOOK_ENDPOINT = Config.get_param('microsoft.outlook.endpoint', self._OUTLOOK_ENDPOINT)
|
||||
|
||||
for record in self:
|
||||
if not record.id or not record.use_microsoft_outlook_service or not record.is_microsoft_outlook_configured:
|
||||
if not record.id or not record.is_microsoft_outlook_configured:
|
||||
record.microsoft_outlook_uri = False
|
||||
continue
|
||||
|
||||
record.microsoft_outlook_uri = url_join(self._OUTLOOK_ENDPOINT, 'authorize?%s' % url_encode({
|
||||
record.microsoft_outlook_uri = url_join(OUTLOOK_ENDPOINT, 'authorize?%s' % url_encode({
|
||||
'client_id': microsoft_outlook_client_id,
|
||||
'response_type': 'code',
|
||||
'redirect_uri': url_join(base_url, '/microsoft_outlook/confirm'),
|
||||
@@ -79,7 +78,7 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
||||
if not self.env.user.has_group('base.group_system'):
|
||||
raise AccessError(_('Only the administrator can link an Outlook mail server.'))
|
||||
|
||||
if not self.use_microsoft_outlook_service or not self.is_microsoft_outlook_configured:
|
||||
if not self.is_microsoft_outlook_configured:
|
||||
raise UserError(_('Please configure your Outlook credentials.'))
|
||||
|
||||
return {
|
||||
@@ -124,9 +123,10 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
||||
base_url = self.get_base_url()
|
||||
microsoft_outlook_client_id = Config.get_param('microsoft_outlook_client_id')
|
||||
microsoft_outlook_client_secret = Config.get_param('microsoft_outlook_client_secret')
|
||||
OUTLOOK_ENDPOINT = Config.get_param('microsoft.outlook.endpoint', self._OUTLOOK_ENDPOINT)
|
||||
|
||||
response = requests.post(
|
||||
url_join(self._OUTLOOK_ENDPOINT, 'token'),
|
||||
url_join(OUTLOOK_ENDPOINT, 'token'),
|
||||
data={
|
||||
'client_id': microsoft_outlook_client_id,
|
||||
'client_secret': microsoft_outlook_client_secret,
|
||||
@@ -159,7 +159,7 @@ class MicrosoftOutlookMixin(models.AbstractModel):
|
||||
or not self.microsoft_outlook_access_token_expiration \
|
||||
or self.microsoft_outlook_access_token_expiration < now_timestamp:
|
||||
if not self.microsoft_outlook_refresh_token:
|
||||
raise UserError(_('Please login your Outlook mail server before using it.'))
|
||||
raise UserError(_('Please connect with your Outlook account before using it.'))
|
||||
(
|
||||
self.microsoft_outlook_access_token,
|
||||
self.microsoft_outlook_access_token_expiration,
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" ?><svg id="Capa_1" style="enable-background:new 0 0 128 128;" version="1.1" viewBox="0 0 128 128" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style type="text/css">
|
||||
.st0{fill:#21A365;}
|
||||
.st1{fill:#107C41;}
|
||||
.st2{fill:#185B37;}
|
||||
.st3{fill:#33C481;}
|
||||
.st4{fill:#17864C;}
|
||||
.st5{fill:#FFFFFF;}
|
||||
.st6{fill:#036C70;}
|
||||
.st7{fill:#1A9BA1;}
|
||||
.st8{fill:#37C6D0;}
|
||||
.st9{fill:#04878B;}
|
||||
.st10{fill:#4F59CA;}
|
||||
.st11{fill:#7B82EA;}
|
||||
.st12{fill:#4C53BB;}
|
||||
.st13{fill:#0F78D5;}
|
||||
.st14{fill:#29A7EB;}
|
||||
.st15{fill:#0358A8;}
|
||||
.st16{fill:#0F79D6;}
|
||||
.st17{fill:#038387;}
|
||||
.st18{fill:#048A8E;}
|
||||
.st19{fill:#C8421D;}
|
||||
.st20{fill:#FF8F6A;}
|
||||
.st21{fill:#ED6B47;}
|
||||
.st22{fill:#891323;}
|
||||
.st23{fill:#AF2131;}
|
||||
.st24{fill:#C94E60;}
|
||||
.st25{fill:#E08195;}
|
||||
.st26{fill:#B42839;}
|
||||
.st27{fill:#0464B8;}
|
||||
.st28{fill:#0377D4;}
|
||||
.st29{fill:#4FD8FF;}
|
||||
.st30{fill:#1681D7;}
|
||||
.st31{fill:#0178D4;}
|
||||
.st32{fill:#042071;}
|
||||
.st33{fill:#168FDE;}
|
||||
.st34{fill:#CA64EA;}
|
||||
.st35{fill:#7E1FAF;}
|
||||
.st36{fill:#AE4BD5;}
|
||||
.st37{fill:#9332BF;}
|
||||
.st38{fill:#7719AA;}
|
||||
.st39{fill:#0078D4;}
|
||||
.st40{fill:#1490DF;}
|
||||
.st41{fill:#0364B8;}
|
||||
.st42{fill:#28A8EA;}
|
||||
.st43{fill:#41A5ED;}
|
||||
.st44{fill:#2C7BD5;}
|
||||
.st45{fill:#195ABE;}
|
||||
.st46{fill:#103E91;}
|
||||
.st47{fill:#2166C3;}
|
||||
.st48{opacity:0.2;}
|
||||
</style><g><path class="st27" d="M120.2,22.8H34.2V9.1C34.2,6.8,36,5,38.2,5h77.9c2.3,0,4.1,1.8,4.1,4.1V22.8z"/><rect class="st28" height="26.6" width="28.7" x="34.2" y="22.8"/><rect class="st14" height="26.6" width="28.7" x="62.9" y="22.8"/><rect class="st29" height="26.6" width="28.7" x="91.6" y="22.8"/><rect class="st30" height="26.6" width="28.7" x="34.2" y="49.4"/><rect class="st31" height="26.6" width="28.7" x="62.9" y="49.4"/><rect class="st14" height="26.6" width="28.7" x="91.6" y="49.4"/><rect class="st27" height="26.6" width="28.7" x="62.9" y="75.9"/><rect class="st30" height="26.6" width="28.7" x="91.6" y="75.9"/></g><path class="st32" d="M126.9,69.1l-6.6,3.9V61.8l6.5,3.6C128.3,66.1,128.3,68.2,126.9,69.1z"/><path class="st33" d="M126.9,69.1l-0.6,0.4l0,0l-0.7,0.4l-5.3,3.1v-0.1l-88.4,50.6h89.1c3.8,0,6.8-3.1,6.8-6.8l0.1-49.4 C128,67.9,127.6,68.7,126.9,69.1z"/><g><path class="st14" d="M122,123.5H32.8c-3.8,0-6.8-3.1-6.8-6.8V68.5L122,123.5z"/></g><path class="st30" d="M59,96.5h-53c-3.5,0-6.4-2.9-6.4-6.4V37.9c0-3.5,2.9-6.4,6.4-6.4h53c3.5,0,6.4,2.9,6.4,6.4v52.2 C65.4,93.6,62.6,96.5,59,96.5z"/><g><path class="st5" d="M32.5,82.9c-10.3,0-16.8-7.8-16.8-18.2c0-11,7.1-18.8,17.3-18.8c10.6,0,16.8,7.9,16.8,18.1 C49.9,76.1,42.5,82.9,32.5,82.9L32.5,82.9z M32.9,77.7c6.4,0,10-5.9,10-13.4c0-6.8-3.4-13.1-10-13.1s-10.1,6.2-10.1,13.4 S26.4,77.7,32.9,77.7L32.9,77.7z"/></g><path class="st48" d="M65.5,37.3c0,0.2,0,0.4,0,0.6v52.2c0,3.5-2.9,6.4-6.4,6.4H26v5.7h38.4c3.5,0,6.4-2.9,6.4-6.4V43.6 C70.8,40.4,68.5,37.7,65.5,37.3z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
+2
-12
@@ -21,12 +21,11 @@ class TestFetchmailOutlook(TransactionCase):
|
||||
|
||||
mail_server = self.env['fetchmail.server'].create({
|
||||
'name': 'Test server',
|
||||
'use_microsoft_outlook_service': True,
|
||||
'server_type': 'outlook',
|
||||
'user': 'test@example.com',
|
||||
'microsoft_outlook_access_token': 'test_access_token',
|
||||
'microsoft_outlook_access_token_expiration': time.time() + 1000000,
|
||||
'password': '',
|
||||
'server_type': 'imap',
|
||||
'is_ssl': True,
|
||||
})
|
||||
|
||||
@@ -45,15 +44,6 @@ class TestFetchmailOutlook(TransactionCase):
|
||||
with self.assertRaises(UserError, msg='Should ensure that the password is empty'):
|
||||
self.env['fetchmail.server'].create({
|
||||
'name': 'Test server',
|
||||
'use_microsoft_outlook_service': True,
|
||||
'server_type': 'outlook',
|
||||
'password': 'test',
|
||||
'server_type': 'imap',
|
||||
})
|
||||
|
||||
with self.assertRaises(UserError, msg='Should ensure that the server type is IMAP'):
|
||||
self.env['fetchmail.server'].create({
|
||||
'name': 'Test server',
|
||||
'use_microsoft_outlook_service': True,
|
||||
'password': '',
|
||||
'server_type': 'pop',
|
||||
})
|
||||
+12
-18
@@ -6,42 +6,36 @@
|
||||
<field name="priority">1000</field>
|
||||
<field name="inherit_id" ref="fetchmail.view_email_server_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="server" position="before">
|
||||
<field name="use_microsoft_outlook_service" string="Outlook"
|
||||
attrs="{'readonly': [('state', '=', 'done')]}"/>
|
||||
</field>
|
||||
<field name="user" position="after">
|
||||
<field name="is_microsoft_outlook_configured" invisible="1"/>
|
||||
<field name="microsoft_outlook_refresh_token" invisible="1"/>
|
||||
<field name="microsoft_outlook_access_token" invisible="1"/>
|
||||
<field name="microsoft_outlook_access_token_expiration" invisible="1"/>
|
||||
<div></div>
|
||||
<div attrs="{'invisible': [('use_microsoft_outlook_service', '=', False)]}">
|
||||
<span attrs="{'invisible': ['|', ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '=', False)]}"
|
||||
<div attrs="{'invisible': [('server_type', '!=', 'outlook')]}"
|
||||
class="d-flex flex-row align-items-center" colspan="8">
|
||||
<span attrs="{'invisible': ['|', ('server_type', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '=', False)]}"
|
||||
class="badge text-bg-success">
|
||||
Outlook Token Valid
|
||||
</span>
|
||||
<button type="object"
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '!=', False)]}">
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('server_type', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '!=', False)]}">
|
||||
<i class="fa fa-arrow-right"/>
|
||||
Connect your Outlook account
|
||||
</button>
|
||||
<button type="object"
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog"/>
|
||||
Edit Settings
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0 ml-2"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('server_type', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog" title="Edit Settings"/>
|
||||
</button>
|
||||
<div class="alert alert-warning" role="alert"
|
||||
attrs="{'invisible': ['|', ('is_microsoft_outlook_configured', '=', True), ('use_microsoft_outlook_service', '=', False)]}">
|
||||
<button class="alert alert-warning d-block mt-2 text-left"
|
||||
icon="fa-arrow-right" type="action" role="alert"
|
||||
name="%(base.res_config_setting_act_window)d"
|
||||
attrs="{'invisible': ['|', ('is_microsoft_outlook_configured', '=', True), ('server_type', '!=', 'outlook')]}">
|
||||
Setup your Outlook API credentials in the general settings to link a Outlook account.
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
<field name="password" position="attributes">
|
||||
<attribute name="attrs">{}</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -5,38 +5,42 @@
|
||||
<field name="model">ir.mail_server</field>
|
||||
<field name="inherit_id" ref="base.ir_mail_server_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="smtp_host" position="before">
|
||||
<field name="use_microsoft_outlook_service" string="Outlook"/>
|
||||
</field>
|
||||
<field name="smtp_user" position="after">
|
||||
<field name="is_microsoft_outlook_configured" invisible="1"/>
|
||||
<field name="microsoft_outlook_refresh_token" invisible="1"/>
|
||||
<field name="microsoft_outlook_access_token" invisible="1"/>
|
||||
<field name="microsoft_outlook_access_token_expiration" invisible="1"/>
|
||||
<div></div>
|
||||
<div attrs="{'invisible': [('use_microsoft_outlook_service', '=', False)]}">
|
||||
<span attrs="{'invisible': ['|', ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '=', False)]}"
|
||||
<div attrs="{'invisible': [('smtp_authentication', '!=', 'outlook')]}"
|
||||
class="d-flex flex-row align-items-center" colspan="8">
|
||||
<span attrs="{'invisible': ['|', ('smtp_authentication', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '=', False)]}"
|
||||
class="badge text-bg-success">
|
||||
Outlook Token Valid
|
||||
</span>
|
||||
<button type="object"
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '!=', False)]}">
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('smtp_authentication', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '!=', False)]}">
|
||||
<i class="fa fa-arrow-right"/>
|
||||
Connect your Outlook account
|
||||
</button>
|
||||
<button type="object"
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('use_microsoft_outlook_service', '=', False), ('microsoft_outlook_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog"/>
|
||||
Edit Settings
|
||||
name="open_microsoft_outlook_uri" class="btn-link px-0 ml-2"
|
||||
attrs="{'invisible': ['|', '|', ('is_microsoft_outlook_configured', '=', False), ('smtp_authentication', '!=', 'outlook'), ('microsoft_outlook_refresh_token', '=', False)]}">
|
||||
<i class="fa fa-cog" title="Edit Settings"/>
|
||||
</button>
|
||||
<div class="alert alert-warning" role="alert"
|
||||
attrs="{'invisible': ['|', ('is_microsoft_outlook_configured', '=', True), ('use_microsoft_outlook_service', '=', False)]}">
|
||||
<button class="alert alert-warning d-block mt-2 text-left"
|
||||
icon="fa-arrow-right" type="action" role="alert"
|
||||
name="%(base.res_config_setting_act_window)d"
|
||||
attrs="{'invisible': ['|', ('is_microsoft_outlook_configured', '=', True), ('smtp_authentication', '!=', 'outlook')]}">
|
||||
Setup your Outlook API credentials in the general settings to link a Outlook account.
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</field>
|
||||
<field name="smtp_authentication_info" position="after">
|
||||
<a href="https://www.odoo.com/documentation/15.0/applications/general/email_communication/email_servers.html?highlight=outgoing email server#use-a-default-from-email-address"
|
||||
attrs="{'invisible': [('smtp_authentication', '!=', 'outlook')]}" target="_blank">
|
||||
Read More
|
||||
</a>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -6,27 +6,18 @@
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<div id="emails" position="inside">
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="microsoft_outlook_setting"
|
||||
attrs="{'invisible': [('external_email_server_default', '=', False)]}">
|
||||
<div class="o_setting_right_pane">
|
||||
<span class="o_form_label">Outlook Credentials</span>
|
||||
<div class="text-muted">
|
||||
Send and receive email with your Outlook account.
|
||||
</div>
|
||||
<div class="content-group">
|
||||
<div class="row mt16" id="outlook_client_identifier">
|
||||
<label string="Client ID" for="microsoft_outlook_client_identifier"
|
||||
class="col-lg-3 o_light_label"/>
|
||||
<field name="microsoft_outlook_client_identifier" class="ms-2"/>
|
||||
</div>
|
||||
<div class="row mt16" id="outlook_client_secret">
|
||||
<label string="Client Secret" for="microsoft_outlook_client_secret"
|
||||
class="col-lg-3 o_light_label"/>
|
||||
<field name="microsoft_outlook_client_secret" class="ms-2"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="msg_module_microsoft_outlook" position="replace">
|
||||
<div class="row mt16" id="outlook_client_identifier">
|
||||
<label string="ID" for="microsoft_outlook_client_identifier"
|
||||
class="col-lg-3 o_light_label"/>
|
||||
<field name="microsoft_outlook_client_identifier" class="ms-2"
|
||||
placeholder="ID of your Outlook app"/>
|
||||
</div>
|
||||
<div class="row mt16" id="outlook_client_secret">
|
||||
<label string="Secret" for="microsoft_outlook_client_secret"
|
||||
class="col-lg-3 o_light_label"/>
|
||||
<field name="microsoft_outlook_client_secret" class="ms-2"
|
||||
placeholder="Secret of your Outlook app"/>
|
||||
</div>
|
||||
</div>
|
||||
</field>
|
||||
|
||||
@@ -95,6 +95,7 @@ class IrMailServer(models.Model):
|
||||
smtp_host = fields.Char(string='SMTP Server', required=True, help="Hostname or IP of SMTP server")
|
||||
smtp_port = fields.Integer(string='SMTP Port', required=True, default=25, help="SMTP Port. Usually 465 for SSL, and 25 or 587 for other cases.")
|
||||
smtp_authentication = fields.Selection([('login', 'Username'), ('certificate', 'SSL Certificate')], string='Authenticate with', required=True, default='login')
|
||||
smtp_authentication_info = fields.Text('Authentication Info', compute='_compute_smtp_authentication_info')
|
||||
smtp_user = fields.Char(string='Username', help="Optional username for SMTP authentication", groups='base.group_system')
|
||||
smtp_pass = fields.Char(string='Password', help="Optional password for SMTP authentication", groups='base.group_system')
|
||||
smtp_encryption = fields.Selection([('none', 'None'),
|
||||
@@ -118,6 +119,21 @@ class IrMailServer(models.Model):
|
||||
"is used. Default priority is 10 (smaller number = higher priority)")
|
||||
active = fields.Boolean(default=True)
|
||||
|
||||
@api.depends('smtp_authentication')
|
||||
def _compute_smtp_authentication_info(self):
|
||||
for server in self:
|
||||
if server.smtp_authentication == 'login':
|
||||
server.smtp_authentication_info = _(
|
||||
'Connect to your server through your usual username and password. \n'
|
||||
'This is the most basic SMTP authentication process and '
|
||||
'may not be accepted by all providers. \n')
|
||||
elif server.smtp_authentication == 'certificate':
|
||||
server.smtp_authentication_info = _(
|
||||
'Authenticate by using SSL certificates, belonging to your domain name. \n'
|
||||
'SSL certificates allow you to authenticate your mail server for the entire domain name.')
|
||||
else:
|
||||
server.smtp_authentication = False
|
||||
|
||||
@api.constrains('smtp_ssl_certificate', 'smtp_ssl_private_key')
|
||||
def _check_smtp_ssl_files(self):
|
||||
"""We must provided both files or none."""
|
||||
|
||||
@@ -10,27 +10,47 @@
|
||||
name="test_smtp_connection" class="btn-primary"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group col="4">
|
||||
<field name="name" placeholder="e.g. My Outgoing Server"/>
|
||||
<field name="from_filter"/>
|
||||
<field name="sequence"/>
|
||||
<field name="active" widget="boolean_toggle"/>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="bg-danger"
|
||||
attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name" placeholder="e.g. My Outgoing Server"/>
|
||||
<field name="from_filter"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="sequence"/>
|
||||
<field name="active" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Authentication">
|
||||
<group>
|
||||
<field name="smtp_authentication" widget="radio"/>
|
||||
<field name="smtp_user" attrs="{'invisible': [('smtp_authentication', '!=', 'login')]}" force_save="1"/>
|
||||
<field name="smtp_pass" attrs="{'invisible': [('smtp_authentication', '!=', 'login')]}" password="True" force_save="1"/>
|
||||
<field name="smtp_ssl_certificate" attrs="{'invisible': [('smtp_authentication', '!=', 'certificate')]}" force_save="1"/>
|
||||
<field name="smtp_ssl_private_key" attrs="{'invisible': [('smtp_authentication', '!=', 'certificate')]}" force_save="1"/>
|
||||
</group>
|
||||
<group string="Connection">
|
||||
<field name="smtp_encryption" widget="radio"/>
|
||||
<field name="smtp_host"/>
|
||||
<field name="smtp_port" options="{'format': false}"/>
|
||||
<field name="smtp_debug" groups="base.group_no_one"/>
|
||||
<group>
|
||||
<div class="text-muted font-italic" role="alert"
|
||||
attrs="{'invisible': [('smtp_authentication_info', '=', False)]}">
|
||||
<field name="smtp_authentication_info"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4">
|
||||
<page name="connection" string="Connection">
|
||||
<group>
|
||||
<group>
|
||||
<field name="smtp_encryption" widget="radio"/>
|
||||
<field name="smtp_host"/>
|
||||
<field name="smtp_port" options="{'format': false}"/>
|
||||
<field name="smtp_debug" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="smtp_user" attrs="{'invisible': [('smtp_authentication', '=', 'certificate')]}" force_save="1"/>
|
||||
<field name="smtp_pass" attrs="{'invisible': [('smtp_authentication', '!=', 'login')]}" password="True" force_save="1"/>
|
||||
<field name="smtp_ssl_certificate" attrs="{'invisible': [('smtp_authentication', '!=', 'certificate')]}" force_save="1"/>
|
||||
<field name="smtp_ssl_private_key" attrs="{'invisible': [('smtp_authentication', '!=', 'certificate')]}" force_save="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
Reference in New Issue
Block a user