Compare commits
3 Commits
01c79fcfff
...
2706479d9f
| Author | SHA1 | Date | |
|---|---|---|---|
| 2706479d9f | |||
|
|
fe8680941a | ||
|
|
3da7ae2cb8 |
@@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
from . import controllers
|
from . import controllers
|
||||||
from . import models
|
from . import models
|
||||||
|
from . import wizard
|
||||||
|
from .hooks import post_init_hook
|
||||||
@@ -17,7 +17,10 @@
|
|||||||
'module_type': 'official',
|
'module_type': 'official',
|
||||||
'depends': ['mail','base',],
|
'depends': ['mail','base',],
|
||||||
'data': [
|
'data': [
|
||||||
|
'wizard/install_warning_wizard_view.xml',
|
||||||
'views/views.xml',
|
'views/views.xml',
|
||||||
'data/data.xml'
|
'data/data.xml',
|
||||||
|
'security/ir.model.access.csv',
|
||||||
],
|
],
|
||||||
|
'post_init_hook': 'post_init_hook',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,55 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# Copyright 2024 Open2Bizz <info@open2bizz.nl>
|
||||||
# from odoo import http
|
# License LGPL-3
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request, Response
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
MAILHOG_BASE = "http://localhost:8025"
|
||||||
|
|
||||||
|
|
||||||
# class TestserverO2b(http.Controller):
|
class MailcatcherProxy(http.Controller):
|
||||||
# @http.route('/testserver_o2b/testserver_o2b/', auth='public')
|
|
||||||
# def index(self, **kw):
|
|
||||||
# return "Hello, world"
|
|
||||||
|
|
||||||
# @http.route('/testserver_o2b/testserver_o2b/objects/', auth='public')
|
@http.route(['/mailcatcher', '/mailcatcher/<path:subpath>'],
|
||||||
# def list(self, **kw):
|
type='http', auth='user', website=False, csrf=False)
|
||||||
# return http.request.render('testserver_o2b.listing', {
|
def mailcatcher_proxy(self, subpath='', **kw):
|
||||||
# 'root': '/testserver_o2b/testserver_o2b',
|
"""Proxy requests to the local MailHog instance."""
|
||||||
# 'objects': http.request.env['testserver_o2b.testserver_o2b'].search([]),
|
target_url = f"{MAILHOG_BASE}/{subpath}"
|
||||||
# })
|
if request.httprequest.query_string:
|
||||||
|
target_url += '?' + request.httprequest.query_string.decode('utf-8')
|
||||||
|
|
||||||
# @http.route('/testserver_o2b/testserver_o2b/objects/<model("testserver_o2b.testserver_o2b"):obj>/', auth='public')
|
try:
|
||||||
# def object(self, obj, **kw):
|
headers = {
|
||||||
# return http.request.render('testserver_o2b.object', {
|
k: v for k, v in request.httprequest.headers
|
||||||
# 'object': obj
|
if k.lower() not in ('host', 'cookie', 'authorization')
|
||||||
# })
|
}
|
||||||
|
resp = requests.request(
|
||||||
|
method=request.httprequest.method,
|
||||||
|
url=target_url,
|
||||||
|
headers=headers,
|
||||||
|
data=request.httprequest.get_data(),
|
||||||
|
timeout=30,
|
||||||
|
allow_redirects=False,
|
||||||
|
)
|
||||||
|
except requests.exceptions.ConnectionError:
|
||||||
|
_logger.warning("Could not connect to MailHog at %s", MAILHOG_BASE)
|
||||||
|
return Response("MailHog is not available", status=502)
|
||||||
|
|
||||||
|
excluded_headers = {
|
||||||
|
'content-encoding', 'content-length', 'transfer-encoding',
|
||||||
|
'connection',
|
||||||
|
}
|
||||||
|
response_headers = [
|
||||||
|
(k, v) for k, v in resp.headers.items()
|
||||||
|
if k.lower() not in excluded_headers
|
||||||
|
]
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
resp.content,
|
||||||
|
status=resp.status_code,
|
||||||
|
headers=response_headers,
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
<function model="ir.config_parameter" name="_mailcatcher_url"/>
|
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
40
mailcatcher_menu/hooks.py
Normal file
40
mailcatcher_menu/hooks.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Copyright 2024 Open2Bizz <info@open2bizz.nl>
|
||||||
|
# License LGPL-3
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def post_init_hook(env):
|
||||||
|
"""Install MailHog as a systemd service when the module is installed."""
|
||||||
|
script_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
'install_mailhog_as_service.sh',
|
||||||
|
)
|
||||||
|
|
||||||
|
if not os.path.isfile(script_path):
|
||||||
|
_logger.error("MailHog install script not found at %s", script_path)
|
||||||
|
return
|
||||||
|
|
||||||
|
_logger.info("Running MailHog install script: %s", script_path)
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['bash', script_path],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=300,
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
_logger.info("MailHog installed successfully.\n%s", result.stdout)
|
||||||
|
else:
|
||||||
|
_logger.error(
|
||||||
|
"MailHog install script failed (exit %s):\n%s\n%s",
|
||||||
|
result.returncode, result.stdout, result.stderr,
|
||||||
|
)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
_logger.error("MailHog install script timed out after 300 seconds")
|
||||||
|
except Exception as e:
|
||||||
|
_logger.error("Failed to run MailHog install script: %s", e)
|
||||||
86
mailcatcher_menu/install_mailhog_as_service.sh
Normal file
86
mailcatcher_menu/install_mailhog_as_service.sh
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e # stop bij fouten
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Update apt..."
|
||||||
|
echo "==================================="
|
||||||
|
apt update
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Install dependencies..."
|
||||||
|
echo "==================================="
|
||||||
|
apt-get -y install wget tar
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Install Go 1.24.3..."
|
||||||
|
echo "==================================="
|
||||||
|
GO_VERSION=1.24.3
|
||||||
|
wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz
|
||||||
|
|
||||||
|
sudo rm -rf /usr/local/go
|
||||||
|
sudo tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz
|
||||||
|
|
||||||
|
# Go environment correct instellen
|
||||||
|
export GOROOT=/usr/local/go
|
||||||
|
export GOPATH=$HOME/go
|
||||||
|
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
|
||||||
|
|
||||||
|
echo "Go version:"
|
||||||
|
go version
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Installing MailHog..."
|
||||||
|
echo "==================================="
|
||||||
|
/usr/local/go/bin/go install github.com/mailhog/MailHog@latest
|
||||||
|
|
||||||
|
if [ -f "$HOME/go/bin/MailHog" ]; then
|
||||||
|
echo "MailHog installed successfully"
|
||||||
|
else
|
||||||
|
echo "ERROR: MailHog binary not found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Copy MailHog to /usr/local/bin..."
|
||||||
|
echo "==================================="
|
||||||
|
sudo cp "$HOME/go/bin/MailHog" /usr/local/bin/MailHog
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Create MailHog service..."
|
||||||
|
echo "==================================="
|
||||||
|
sudo tee /etc/systemd/system/mailhog.service > /dev/null <<EOL
|
||||||
|
[Unit]
|
||||||
|
Description=MailHog
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=root
|
||||||
|
ExecStart=/usr/local/bin/MailHog
|
||||||
|
Restart=always
|
||||||
|
Environment="PATH=/usr/local/go/bin:/usr/bin:/bin"
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOL
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "Enable + start MailHog service..."
|
||||||
|
echo "==================================="
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable mailhog
|
||||||
|
systemctl start mailhog
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================================="
|
||||||
|
echo "MailHog is running!"
|
||||||
|
echo "Web UI: http://localhost:8025"
|
||||||
|
echo "SMTP: localhost:1025"
|
||||||
|
echo "==================================="
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from . import mailcatcher_menu
|
# No models needed — MailHog is accessed via the proxy controller
|
||||||
|
|||||||
@@ -1,27 +1,7 @@
|
|||||||
# Copyright 2024 Open2Bizz <info@open2bizz.nl>
|
# Copyright 2024 Open2Bizz <info@open2bizz.nl>
|
||||||
# License LGPL-3
|
# License LGPL-3
|
||||||
|
|
||||||
from odoo import api, fields, models, _
|
# MailHog is now accessed via the internal proxy controller at /mailcatcher/
|
||||||
|
# so no dynamic URL computation is needed anymore.
|
||||||
import logging
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class IrActionUrl(models.Model):
|
|
||||||
_inherit = "ir.config_parameter"
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
#def init(self):
|
|
||||||
def _mailcatcher_url(self):
|
|
||||||
parameters = self.env['ir.config_parameter'].search([('key','=', 'web.base.url')])
|
|
||||||
if parameters:
|
|
||||||
parameter = parameters[0]
|
|
||||||
cont_nr = parameter.value.split("//",1)[1] #Haal https:// van string
|
|
||||||
cont_nr = cont_nr[0:3] #De eerste 3 karakters is het containernummer
|
|
||||||
act_url = "https://" + cont_nr + "-mailcatcher.staging.open2bizz.com"
|
|
||||||
_logger.info('---------- ACT_URL ---------- %s', act_url)
|
|
||||||
action_id = self.env['ir.model.data']._xmlid_to_res_id('mailcatcher_menu.action_mailcatcher_url')
|
|
||||||
action = self.env['ir.actions.act_url'].browse(action_id)
|
|
||||||
if action:
|
|
||||||
action.write({'url':act_url})
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||||
"access_mailcatcher_menu_mailcatcher_menu","mailcatcher_menu.mailcatcher_menu","model_mailcatcher_menu_mailcatcher_menu","base.group_user",1,1,1,1
|
"access_mailcatcher_install_warning_wizard","mailcatcher.install.warning.wizard","model_mailcatcher_install_warning_wizard","base.group_user",1,1,1,1
|
||||||
|
|||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<record model="ir.actions.act_url" id="action_mailcatcher_url">
|
<record model="ir.actions.act_url" id="action_mailcatcher_url">
|
||||||
<field name="name">Open Mailcatcher</field>
|
<field name="name">Open Mailcatcher</field>
|
||||||
<field name="url">https://mailcatcher.staging.open2bizz.com</field>
|
<field name="url">/mailcatcher/</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
3
mailcatcher_menu/wizard/__init__.py
Normal file
3
mailcatcher_menu/wizard/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import install_warning_wizard
|
||||||
43
mailcatcher_menu/wizard/install_warning_wizard.py
Normal file
43
mailcatcher_menu/wizard/install_warning_wizard.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Copyright 2024 Open2Bizz <info@open2bizz.nl>
|
||||||
|
# License LGPL-3
|
||||||
|
|
||||||
|
from odoo import models, fields, api, _
|
||||||
|
|
||||||
|
|
||||||
|
class MailcatcherInstallWarningWizard(models.TransientModel):
|
||||||
|
_name = 'mailcatcher.install.warning.wizard'
|
||||||
|
_description = 'MailCatcher Install Warning'
|
||||||
|
|
||||||
|
module_id = fields.Many2one('ir.module.module', string='Module', readonly=True)
|
||||||
|
|
||||||
|
def action_confirm_install(self):
|
||||||
|
"""User confirmed — proceed with the actual module installation."""
|
||||||
|
self.ensure_one()
|
||||||
|
return self.module_id.with_context(
|
||||||
|
skip_mailcatcher_warning=True
|
||||||
|
).button_immediate_install()
|
||||||
|
|
||||||
|
|
||||||
|
class IrModuleModule(models.Model):
|
||||||
|
_inherit = 'ir.module.module'
|
||||||
|
|
||||||
|
def button_immediate_install(self):
|
||||||
|
"""Override to show a warning before installing mailcatcher_menu."""
|
||||||
|
if self.env.context.get('skip_mailcatcher_warning'):
|
||||||
|
return super().button_immediate_install()
|
||||||
|
|
||||||
|
mailcatcher_modules = self.filtered(lambda m: m.name == 'mailcatcher_menu')
|
||||||
|
if mailcatcher_modules:
|
||||||
|
wizard = self.env['mailcatcher.install.warning.wizard'].create({
|
||||||
|
'module_id': mailcatcher_modules[0].id,
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
'name': _('Install MailCatcher Module'),
|
||||||
|
'type': 'ir.actions.act_window',
|
||||||
|
'res_model': 'mailcatcher.install.warning.wizard',
|
||||||
|
'res_id': wizard.id,
|
||||||
|
'view_mode': 'form',
|
||||||
|
'target': 'new',
|
||||||
|
}
|
||||||
|
|
||||||
|
return super().button_immediate_install()
|
||||||
28
mailcatcher_menu/wizard/install_warning_wizard_view.xml
Normal file
28
mailcatcher_menu/wizard/install_warning_wizard_view.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<odoo>
|
||||||
|
<record id="view_mailcatcher_install_warning_wizard" model="ir.ui.view">
|
||||||
|
<field name="name">mailcatcher.install.warning.wizard.form</field>
|
||||||
|
<field name="model">mailcatcher.install.warning.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Install MailCatcher">
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<h4 class="alert-heading">Warning</h4>
|
||||||
|
<p>
|
||||||
|
You are about to install the <strong>MailCatcher</strong> module.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This will also install <strong>MailHog</strong> as a systemd service on this server.
|
||||||
|
MailHog will listen on port <strong>8025</strong> (Web UI) and port <strong>1025</strong> (SMTP).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Do you want to proceed with the installation?
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<button name="action_confirm_install" type="object"
|
||||||
|
string="Confirm Install" class="btn-primary"/>
|
||||||
|
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user