marc look at .repos/bemade-addons/bemade_mailcow_blacklist/static/src/js/mailcow_mailbox.js please

This commit is contained in:
Benoît Vézina 2023-06-29 20:22:25 -04:00
parent 68dd96a5a8
commit ed021edc40
11 changed files with 138 additions and 40 deletions

View file

@ -21,7 +21,7 @@ Main Features:
'license': 'OPL-1', 'license': 'OPL-1',
'author': 'BeMade', 'author': 'BeMade',
'website': 'https://www.bemade.org', 'website': 'https://www.bemade.org',
'depends': ['mail', 'bemade_user_password_bundle'], 'depends': ['hr', 'mail', 'bemade_user_password_bundle'],
'data': [ 'data': [
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/res_config_settings_views.xml', 'views/res_config_settings_views.xml',
@ -31,6 +31,11 @@ Main Features:
'views/res_users_views.xml', 'views/res_users_views.xml',
], ],
"assets": {
"web.assets_backend": [
"bemade_mailcow_blacklist/static/src/js/mailcow_mailbox.js"
]
},
'demo': [], 'demo': [],
'installable': True, 'installable': True,
'application': False, 'application': False,

View file

@ -6,15 +6,25 @@ class MailAlias(models.Model):
mailcow_id = fields.One2many('mail.mailcow.alias', 'alias_id') mailcow_id = fields.One2many('mail.mailcow.alias', 'alias_id')
@api.model
def create(self, vals): def create(self, vals):
alias = super(MailAlias, self).create(vals) alias = super(MailAlias, self).create(vals)
mailcow_alias = self.env['mail.mailcow.alias'].search([('address', '=', alias.alias_name + '@' + alias.alias_domain)])
alias_domain = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain"),
catchall_alias = self.env["ir.config_parameter"].sudo().get_param("mail.catchall.alias"),
alias_domain = alias_domain[0]
catchall_alias = catchall_alias[0]
if not alias_domain:
raise ValidationError(_("No catchall domain is set in the system parameters. Please set one and try again."))
mailcow_alias = self.env['mail.mailcow.alias'].search([('address', '=', alias.alias_name + '@' + alias_domain)])
if mailcow_alias: if mailcow_alias:
mailcow_alias.write({'active': True}) mailcow_alias.write({'active': True})
else: else:
self.env['mail.mailcow.alias'].create({ self.env['mail.mailcow.alias'].create({
'address': alias.alias_name + '@' + alias.alias_domain, 'address': alias.alias_name + '@' + alias_domain,
'goto': alias.alias_defaults.get('email_from', False), 'goto': catchall_alias + '@' + alias_domain,
'alias_id': alias.id, 'alias_id': alias.id,
}) })
return alias return alias

View file

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import models, fields, api, exceptions from odoo import models, fields, api, _
import requests import requests
import logging import logging
from odoo.exceptions import ValidationError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -10,15 +12,29 @@ class MailMailcow(models.AbstractModel):
_name = 'mail.mailcow' _name = 'mail.mailcow'
_description = 'Mailcow API' _description = 'Mailcow API'
@property
def get_credentials(self): def get_credentials(self):
params = self.env['ir.config_parameter'].sudo() params = self.env['ir.config_parameter'].sudo()
base_url = params.get_param('mailcow.base_url'),
base_url = base_url[0]
api_key = params.get_param('mailcow.api_key'),
api_key = api_key[0]
if not base_url or not api_key:
_logger.error('No API key or base URL is set in the system parameters')
raise ValidationError(_("No API key or base URL is set in the system parameters. Please set one and try again."))
# return False
else:
return { return {
'base_url': params.get_param('mailcow.base_url'), 'base_url': base_url,
'api_key': params.get_param('mailcow.api_key'), 'api_key': api_key
} }
def api_request(self, endpoint, method='GET', data=None): def api_request(self, endpoint, method='GET', data=None):
creds = self.get_credentials() creds = self.get_credentials
if not creds:
return False
url = creds['base_url'] + endpoint url = creds['base_url'] + endpoint
headers = { headers = {
'accept': 'application/json', 'accept': 'application/json',

View file

@ -33,9 +33,10 @@ class MailcowAlias(models.Model):
"private_comment": f"Created by {self.env.user.name} on {fields.Datetime.now()}", "private_comment": f"Created by {self.env.user.name} on {fields.Datetime.now()}",
"public_comment": "Alias created in Odoo" "public_comment": "Alias created in Odoo"
} }
result = self.env['mail.mailcow'].api_request('api/v1/add/alias', 'POST', data) result = self.env['mail.mailcow'].api_request('/api/v1/add/alias', 'POST', data)
if not result: if not result:
raise ValidationError(_("Failed to create alias on Mailcow server.")) #pass
raise ValidationError("Failed to create alias on Mailcow server.")
return alias return alias
@ -59,7 +60,7 @@ class MailcowAlias(models.Model):
}, },
"items": [record.mc_id] "items": [record.mc_id]
} }
result = self.env['mail.mailcow'].api_request('api/v1/edit/alias', 'POST', data) result = self.env['mail.mailcow'].api_request('/api/v1/edit/alias', 'POST', data)
if not result: if not result:
raise ValidationError(_("Failed to update alias on Mailcow server.")) raise ValidationError(_("Failed to update alias on Mailcow server."))
@ -72,7 +73,7 @@ class MailcowAlias(models.Model):
For each alias fetched from Mailcow server, it tries to find a matching record For each alias fetched from Mailcow server, it tries to find a matching record
in Odoo. If it doesn't exist, it creates a new record. in Odoo. If it doesn't exist, it creates a new record.
""" """
endpoint = 'api/v1/get/alias/all' endpoint = '/api/v1/get/alias/all'
mailcow_aliases = self.api_request(endpoint) mailcow_aliases = self.api_request(endpoint)
if not mailcow_aliases: if not mailcow_aliases:
@ -80,6 +81,7 @@ class MailcowAlias(models.Model):
for mc_alias in mailcow_aliases: for mc_alias in mailcow_aliases:
domain = mc_alias['domain'] domain = mc_alias['domain']
alias_domain = self.env['ir.config_parameter'].sudo().get_param('mail.catchall.domain') alias_domain = self.env['ir.config_parameter'].sudo().get_param('mail.catchall.domain')
if domain == alias_domain: if domain == alias_domain:
alias = self.search([('address', '=', mc_alias['address'])], limit=1) alias = self.search([('address', '=', mc_alias['address'])], limit=1)

View file

@ -10,8 +10,8 @@ class MailcowBlacklist(models.Model):
_description = 'Mailcow Blacklist' _description = 'Mailcow Blacklist'
_inherit = ['mail.mailcow', 'mail.thread', 'mail.activity.mixin'] _inherit = ['mail.mailcow', 'mail.thread', 'mail.activity.mixin']
email = fields.Char(string='Email', required=True, track_visibility='onchange') email = fields.Char(string='Email', required=True, tracking=True)
prefid = fields.Integer(string='Mailcow ID', required=True, track_visibility='onchange') prefid = fields.Integer(string='Mailcow ID', required=True, tracking=True)
@api.model @api.model
def create(self, vals): def create(self, vals):
@ -19,10 +19,10 @@ class MailcowBlacklist(models.Model):
Overridden create method to add the new blacklist entry to the Mailcow server. Overridden create method to add the new blacklist entry to the Mailcow server.
""" """
res = super().create(vals) res = super().create(vals)
domain = self.env['res.config.settings'].get_values()['mail.catchall.domain'] domain = self.env['ir.config_parameter'].sudo().get_param('mail.catchall.domain')
endpoint_add = 'api/v1/add/domain-policy' endpoint_add = '/api/v1/add/domain-policy'
endpoint_get_bl = f"api/v1/get/policy_bl_domain/{domain}" endpoint_get_bl = f"/api/v1/get/policy_bl_domain/{domain}"
data = { data = {
'domain': domain, 'domain': domain,
'object_from': res.email, 'object_from': res.email,
@ -42,8 +42,8 @@ class MailcowBlacklist(models.Model):
old_email = self.email old_email = self.email
res = super().write(vals) res = super().write(vals)
if 'email' in vals: if 'email' in vals:
delete_endpoint = 'api/v1/delete/domain-policy' delete_endpoint = '/api/v1/delete/domain-policy'
add_endpoint = 'api/v1/add/domain-policy' add_endpoint = '/api/v1/add/domain-policy'
delete_data = { delete_data = {
'items': [old_email] 'items': [old_email]
} }
@ -60,7 +60,7 @@ class MailcowBlacklist(models.Model):
Overridden unlink method to remove the blacklist entry from the Mailcow server. Overridden unlink method to remove the blacklist entry from the Mailcow server.
""" """
for record in self: for record in self:
endpoint = 'api/v1/delete/blacklist' endpoint = '/api/v1/delete/blacklist'
data = { data = {
'items': [record.email] 'items': [record.email]
} }

View file

@ -11,13 +11,16 @@ class MailcowMailbox(models.Model):
_inherit = ['mail.mailcow', 'mail.thread', 'mail.activity.mixin'] _inherit = ['mail.mailcow', 'mail.thread', 'mail.activity.mixin']
_description = 'Mailcow Mailbox' _description = 'Mailcow Mailbox'
name = fields.Char(track_visibility='onchange') def _default_domain(self):
address = fields.Char(compute='_compute_address', store=True, readonly=True, track_visibility='onchange') return self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")
local_part = fields.Char(required=True, track_visibility='onchange')
domain = fields.Char(required=True, track_visibility='onchange') name = fields.Char(tracking=True)
active = fields.Boolean(default=True, track_visibility='onchange') address = fields.Char(compute='_compute_address', store=True, readonly=True, tracking=True)
user_id = fields.Many2one('res.users', ondelete='cascade', track_visibility='onchange') local_part = fields.Char(required=True, tracking=True)
password = fields.Char(readonly=True, track_visibility='onchange') domain = fields.Char(required=True, tracking=True, default=_default_domain)
active = fields.Boolean(default=True, tracking=True)
user_id = fields.Many2one('res.users', ondelete='cascade', tracking=True)
password = fields.Char(readonly=True, tracking=True)
@api.depends('local_part', 'domain') @api.depends('local_part', 'domain')
def _compute_address(self): def _compute_address(self):
@ -28,7 +31,7 @@ class MailcowMailbox(models.Model):
""" """
Synchronize Mailcow mailboxes with Odoo Synchronize Mailcow mailboxes with Odoo
""" """
endpoint = 'api/v1/get/mailbox/all' endpoint = '/api/v1/get/mailbox/all'
data = self.api_request(endpoint) data = self.api_request(endpoint)
if data: if data:
for item in data: for item in data:
@ -51,12 +54,12 @@ class MailcowMailbox(models.Model):
vals['password'] = password vals['password'] = password
# Check if email exists on Mailcow # Check if email exists on Mailcow
endpoint = f"api/v1/get/mailbox/{vals['address']}" endpoint = f"/api/v1/get/mailbox/{vals['local_part']}@{vals['domain']}"
response = self.api_request(endpoint) response = self.api_request(endpoint)
if not response: if not response:
# If email does not exist on Mailcow, create it # If email does not exist on Mailcow, create it
endpoint = 'api/v1/add/mailbox' endpoint = '/api/v1/add/mailbox'
data = { data = {
'local_part': vals['local_part'], 'local_part': vals['local_part'],
'domain': vals['domain'], 'domain': vals['domain'],
@ -70,7 +73,7 @@ class MailcowMailbox(models.Model):
'tls_enforce_out': "0", 'tls_enforce_out': "0",
} }
self.api_request(endpoint, method='POST', data=data) self.api_request(endpoint, method='POST', data=data)
_logger.info(f'Mailbox {vals["address"]} has been created on Mailcow server') _logger.info(f"Mailbox {vals['local_part']}@{vals['domain']} has been created on Mailcow server")
return super().create(vals) return super().create(vals)
@ -79,7 +82,7 @@ class MailcowMailbox(models.Model):
Override the write function to update a Mailcow mailbox whenever a user is updated in Odoo. Override the write function to update a Mailcow mailbox whenever a user is updated in Odoo.
""" """
if 'active' in vals or 'local_part' in vals or 'domain' in vals: if 'active' in vals or 'local_part' in vals or 'domain' in vals:
endpoint = f'api/v1/edit/mailbox/{self.address}' endpoint = f'/api/v1/edit/mailbox/{self.address}'
data = { data = {
'items': [self.address], 'items': [self.address],
'attr': { 'attr': {
@ -97,7 +100,7 @@ class MailcowMailbox(models.Model):
""" """
Override the unlink function to delete a Mailcow mailbox whenever a user is deleted in Odoo. Override the unlink function to delete a Mailcow mailbox whenever a user is deleted in Odoo.
""" """
endpoint = f'api/v1/delete/mailbox/{self.address}' endpoint = f'/api/v1/delete/mailbox/{self.address}'
self.api_request(endpoint, method='POST') self.api_request(endpoint, method='POST')
_logger.info(f'Mailbox {self.address} has been deleted on Mailcow server') _logger.info(f'Mailbox {self.address} has been deleted on Mailcow server')
@ -119,7 +122,7 @@ class MailcowMailbox(models.Model):
'name': user.name, 'name': user.name,
'password': user.password, 'password': user.password,
} }
endpoint = 'api/v1/add/mailbox' endpoint = '/api/v1/add/mailbox'
self.api_request(endpoint, method='POST', data=data) self.api_request(endpoint, method='POST', data=data)
_logger.info(f'Mailbox for user {user.login} has been created on Mailcow server') _logger.info(f'Mailbox for user {user.login} has been created on Mailcow server')

View file

@ -5,10 +5,11 @@ class ResUsers(models.Model):
mailcow_mailbox = fields.Boolean(string='Mailcow Mailbox', default=False) mailcow_mailbox = fields.Boolean(string='Mailcow Mailbox', default=False)
@api.model
def create(self, vals): def create(self, vals):
res = super(ResUsers, self).create(vals) res = super(ResUsers, self).create(vals)
if vals.get('mailcow_mailbox'): if vals.get('mailcow_mailbox', false):
self.env['mail.mailcow.mailbox'].create_mailbox_for_user(res) self.env['mail.mailcow.mailbox'].create_mailbox_for_user(res)
return res return res

View file

@ -0,0 +1,30 @@
odoo.define('bemade_mailcow_blacklist.mailcow_mailbox', function (require) {
"use strict";
var core = require('web.core');
var ListController = require('web.ListController');
var ListView = require('web.ListView');
var viewRegistry = require('web.view_registry');
var MailboxesListController = ListController.extend({
buttons_template: 'mail.mailcow_mailbox_list_view_buttons',
events: _.extend({}, ListController.prototype.events, {
'click .o_button_sync_mailboxes': '_onSyncMailboxes',
}),
_onSyncMailboxes: function () {
this._rpc({
model: 'mail.mailcow.mailbox',
method: 'sync_mailboxes',
args: [],
});
},
});
var MailboxesListView = ListView.extend({
config: _.extend({}, ListView.prototype.config, {
Controller: MailboxesListController,
}),
});
viewRegistry.add('mail.mailcow.mailbox', MailboxesListView);
});

View file

@ -0,0 +1 @@
from . import test_mailcow

View file

@ -0,0 +1,12 @@
from odoo.tests.common import TransactionCase, tagged
@tagged('-at_install', 'post_install')
class TestMailcow(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
def test_new_mail_alias(self):
model_id = self.env['ir.model']._get('res.partner').id
self.alias = self.env['mail.alias'].create({'alias_name': 'test', 'alias_model_id': model_id})

View file

@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<record id="mailcow_mailbox_view_tree" model="ir.ui.view"> <record id="view_mailcow_mailbox_tree" model="ir.ui.view">
<field name="name">mailcow.mailbox.view.tree</field> <field name="name">mailcow.mailbox.view.tree</field>
<field name="model">mail.mailcow.mailbox</field> <field name="model">mail.mailcow.mailbox</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Mailbox" decoration-info="active == False"> <tree string="Mailbox" decoration-info="active == False">
<header>
<button name="sync_mailboxes" string="Sync with Mailcow" type="object"/>
</header>
<field name="active"/> <field name="active"/>
<field name="name"/> <field name="name"/>
<field name="local_part"/> <field name="local_part"/>
@ -39,7 +42,7 @@
</field> </field>
</record> </record>
<record id="mailcow_mailbox_action" model="ir.actions.act_window"> <record id="action_mailcow_mailbox" model="ir.actions.act_window">
<field name="name">Mailboxes</field> <field name="name">Mailboxes</field>
<field name="type">ir.actions.act_window</field> <field name="type">ir.actions.act_window</field>
<field name="res_model">mail.mailcow.mailbox</field> <field name="res_model">mail.mailcow.mailbox</field>
@ -62,6 +65,21 @@
<menuitem id="mailcow_menu_mailbox" <menuitem id="mailcow_menu_mailbox"
name="Mailboxes" name="Mailboxes"
parent="mailcow_menu" parent="mailcow_menu"
action="mailcow_mailbox_action" action="action_mailcow_mailbox"
sequence="10"/> sequence="10"/>
<record id="action_server_sync_mailboxes" model="ir.actions.server">
<field name="name">Sync Mailboxes</field>
<field name="model_id" ref="model_mail_mailcow_mailbox"/>
<field name="state">code</field>
<field name="code">model.sync_mailboxes()</field>
</record>
<record id="action_sync_mailboxes" model="ir.actions.act_window.view">
<field name="sequence" eval="10"/>
<field name="view_mode">tree</field>
<field name="act_window_id" ref="action_mailcow_mailbox"/>
<field name="view_id" ref="view_mailcow_mailbox_tree"/>
</record>
</odoo> </odoo>