diff --git a/addons/hw_drivers/connection_manager.py b/addons/hw_drivers/connection_manager.py index 1ae7fb58971..24e1142bac8 100644 --- a/addons/hw_drivers/connection_manager.py +++ b/addons/hw_drivers/connection_manager.py @@ -54,15 +54,12 @@ class ConnectionManager(Thread): _logger.error('A error encountered : %s ' % e) def _connect_to_server(self, url, token, db_uuid, enterprise_code): - if db_uuid and enterprise_code: - helpers.add_credential(db_uuid, enterprise_code) - # Save DB URL and token - subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, '', token, 'noreboot']) + helpers.save_conf_server(url, token, db_uuid, enterprise_code) # Notify the DB, so that the kanban view already shows the IoT Box manager.send_alldevices() # Restart to checkout the git branch, get a certificate, load the IoT handlers... - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + helpers.odoo_restart(2) def _refresh_displays(self): """Refresh all displays to hide the pairing code""" diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py index 3cf12a81d2d..c563879209a 100755 --- a/addons/hw_drivers/controllers/driver.py +++ b/addons/hw_drivers/controllers/driver.py @@ -65,36 +65,6 @@ class DriverController(http.Controller): req['result']['session_id'] = req['session_id'] return req['result'] - @http.route('/hw_drivers/box/connect', type='http', auth='none', cors='*', csrf=False, save_session=False) - def connect_box(self, token): - """ - This route is called when we want that a IoT Box will be connected to a Odoo DB - token is a base 64 encoded string and have 2 argument separate by | - 1 - url of odoo DB - 2 - token. This token will be compared to the token of Odoo. He have 1 hour lifetime - """ - server = helpers.get_odoo_server_url() - image = get_resource_path('hw_drivers', 'static/img', 'False.jpg') - if not server: - credential = b64decode(token).decode('utf-8').split('|') - url = credential[0] - token = credential[1] - if len(credential) > 2: - # IoT Box send token with db_uuid and enterprise_code only since V13 - db_uuid = credential[2] - enterprise_code = credential[3] - helpers.add_credential(db_uuid, enterprise_code) - try: - subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, '', token, 'noreboot']) - manager.send_alldevices() - image = get_resource_path('hw_drivers', 'static/img', 'True.jpg') - helpers.odoo_restart(3) - except subprocess.CalledProcessError as e: - _logger.error('A error encountered : %s ' % e.output) - if os.path.isfile(image): - with open(image, 'rb') as f: - return f.read() - @http.route('/hw_drivers/download_logs', type='http', auth='none', cors='*', csrf=False, save_session=False) def download_logs(self): """ diff --git a/addons/hw_drivers/iot_handlers/drivers/DisplayDriver.py b/addons/hw_drivers/iot_handlers/drivers/DisplayDriver_L.py similarity index 100% rename from addons/hw_drivers/iot_handlers/drivers/DisplayDriver.py rename to addons/hw_drivers/iot_handlers/drivers/DisplayDriver_L.py diff --git a/addons/hw_drivers/iot_handlers/drivers/KeyboardUSBDriver.py b/addons/hw_drivers/iot_handlers/drivers/KeyboardUSBDriver_L.py similarity index 100% rename from addons/hw_drivers/iot_handlers/drivers/KeyboardUSBDriver.py rename to addons/hw_drivers/iot_handlers/drivers/KeyboardUSBDriver_L.py diff --git a/addons/hw_l10n_eg_eta/controllers/main.py b/addons/hw_drivers/iot_handlers/drivers/L10nEGDrivers.py similarity index 100% rename from addons/hw_l10n_eg_eta/controllers/main.py rename to addons/hw_drivers/iot_handlers/drivers/L10nEGDrivers.py diff --git a/addons/hw_drivers/iot_handlers/drivers/PrinterDriver.py b/addons/hw_drivers/iot_handlers/drivers/PrinterDriver_L.py similarity index 99% rename from addons/hw_drivers/iot_handlers/drivers/PrinterDriver.py rename to addons/hw_drivers/iot_handlers/drivers/PrinterDriver_L.py index 36d82b9aadd..1b9dfbeae7d 100644 --- a/addons/hw_drivers/iot_handlers/drivers/PrinterDriver.py +++ b/addons/hw_drivers/iot_handlers/drivers/PrinterDriver_L.py @@ -19,7 +19,7 @@ from odoo.addons.hw_drivers.connection_manager import connection_manager from odoo.addons.hw_drivers.controllers.proxy import proxy_drivers from odoo.addons.hw_drivers.driver import Driver from odoo.addons.hw_drivers.event_manager import event_manager -from odoo.addons.hw_drivers.iot_handlers.interfaces.PrinterInterface import PPDs, conn, cups_lock +from odoo.addons.hw_drivers.iot_handlers.interfaces.PrinterInterface_L import PPDs, conn, cups_lock from odoo.addons.hw_drivers.main import iot_devices from odoo.addons.hw_drivers.tools import helpers diff --git a/addons/hw_drivers/iot_handlers/drivers/PrinterDriver_W.py b/addons/hw_drivers/iot_handlers/drivers/PrinterDriver_W.py new file mode 100644 index 00000000000..a9885788dc4 --- /dev/null +++ b/addons/hw_drivers/iot_handlers/drivers/PrinterDriver_W.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from PIL import Image, ImageOps +import logging +from base64 import b64decode +import io +import win32print +import ghostscript + +from odoo.addons.hw_drivers.controllers.proxy import proxy_drivers +from odoo.addons.hw_drivers.driver import Driver +from odoo.addons.hw_drivers.event_manager import event_manager +from odoo.addons.hw_drivers.main import iot_devices +from odoo.addons.hw_drivers.tools import helpers + +_logger = logging.getLogger(__name__) + +RECEIPT_PRINTER_COMMANDS = { + 'star': { + 'center': b'\x1b\x1d\x61\x01', # ESC GS a n + 'cut': b'\x1b\x64\x02', # ESC d n + 'title': b'\x1b\x69\x01\x01%s\x1b\x69\x00\x00', # ESC i n1 n2 + 'drawers': [b'\x07', b'\x1a'] # BEL & SUB + }, + 'escpos': { + 'center': b'\x1b\x61\x01', # ESC a n + 'cut': b'\x1d\x56\x41\n', # GS V m + 'title': b'\x1b\x21\x30%s\x1b\x21\x00', # ESC ! n + 'drawers': [b'\x1b\x3d\x01', b'\x1b\x70\x00\x19\x19', b'\x1b\x70\x01\x19\x19'] # ESC = n then ESC p m t1 t2 + } +} + +class PrinterDriver(Driver): + connection_type = 'printer' + + def __init__(self, identifier, device): + super().__init__(identifier, device) + self.device_type = 'printer' + self.device_connection = 'network' + self.device_name = device.get('identifier') + self.printer_handle = device.get('printer_handle') + self.state = { + 'status': 'connecting', + 'message': 'Connecting to printer', + 'reason': None, + } + self.send_status() + + self._actions.update({ + 'cashbox': self.open_cashbox, + 'print_receipt': self.print_receipt, + '': self._action_default, + }) + + self.receipt_protocol = 'escpos' + + @classmethod + def supported(cls, device): + return True + + @classmethod + def get_status(cls): + status = 'connected' if any(iot_devices[d].device_type == "printer" and iot_devices[d].device_connection == 'direct' for d in iot_devices) else 'disconnected' + return {'status': status, 'messages': ''} + + def disconnect(self): + self.update_status('disconnected', 'Printer was disconnected') + super(PrinterDriver, self).disconnect() + + def update_status(self, status, message, reason=None): + """Updates the state of the current printer. + + Args: + status (str): The new value of the status + message (str): A comprehensive message describing the status + reason (str): The reason fo the current status + """ + if self.state['status'] != status or self.state['reason'] != reason: + self.state = { + 'status': status, + 'message': message, + 'reason': reason, + } + self.send_status() + + def send_status(self): + """ Sends the current status of the printer to the connected Odoo instance. + """ + self.data = { + 'value': '', + 'state': self.state, + } + event_manager.device_changed(self) + + def print_raw(self, data): + win32print.StartDocPrinter(self.printer_handle, 1, ('', None, "RAW")) + win32print.StartPagePrinter(self.printer_handle) + win32print.WritePrinter(self.printer_handle, data) + win32print.EndPagePrinter(self.printer_handle) + win32print.EndDocPrinter(self.printer_handle) + + def print_report(self, data): + helpers.write_file('document.pdf', data, 'wb') + file_name = helpers.path_file('document.pdf') + printer = self.device_name + + args = [ + "-dPrinted", "-dBATCH", "-dNOSAFER", "-dNOPAUSE", "-dNOPROMPT" + "-q", + "-sDEVICE#mswinpr2", + f'-sOutputFile#%printer%{printer}', + f'{file_name}' + ] + + ghostscript.Ghostscript(*args) + + def print_receipt(self, data): + receipt = b64decode(data['receipt']) + im = Image.open(io.BytesIO(receipt)) + + # Convert to greyscale then to black and white + im = im.convert("L") + im = ImageOps.invert(im) + im = im.convert("1") + + print_command = getattr(self, 'format_%s' % self.receipt_protocol)(im) + self.print_raw(print_command) + + def format_escpos(self, im): + width = int((im.width + 7) / 8) + + raster_send = b'\x1d\x76\x30\x00' + max_slice_height = 255 + + raster_data = b'' + dots = im.tobytes() + while dots: + im_slice = dots[:width*max_slice_height] + slice_height = int(len(im_slice) / width) + raster_data += raster_send + width.to_bytes(2, 'little') + slice_height.to_bytes(2, 'little') + im_slice + dots = dots[width*max_slice_height:] + + return raster_data + RECEIPT_PRINTER_COMMANDS['escpos']['cut'] + + def open_cashbox(self, data): + """Sends a signal to the current printer to open the connected cashbox.""" + commands = RECEIPT_PRINTER_COMMANDS[self.receipt_protocol] + for drawer in commands['drawers']: + self.print_raw(drawer) + + def _action_default(self, data): + self.print_report(b64decode(data['document'])) + +proxy_drivers['printer'] = PrinterDriver diff --git a/addons/hw_drivers/iot_handlers/interfaces/DisplayInterface.py b/addons/hw_drivers/iot_handlers/interfaces/DisplayInterface_L.py similarity index 100% rename from addons/hw_drivers/iot_handlers/interfaces/DisplayInterface.py rename to addons/hw_drivers/iot_handlers/interfaces/DisplayInterface_L.py diff --git a/addons/hw_drivers/iot_handlers/interfaces/PrinterInterface.py b/addons/hw_drivers/iot_handlers/interfaces/PrinterInterface_L.py similarity index 100% rename from addons/hw_drivers/iot_handlers/interfaces/PrinterInterface.py rename to addons/hw_drivers/iot_handlers/interfaces/PrinterInterface_L.py diff --git a/addons/hw_drivers/iot_handlers/interfaces/PrinterInterface_W.py b/addons/hw_drivers/iot_handlers/interfaces/PrinterInterface_W.py new file mode 100644 index 00000000000..c32c52d0f9c --- /dev/null +++ b/addons/hw_drivers/iot_handlers/interfaces/PrinterInterface_W.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import win32print + +from odoo.addons.hw_drivers.interface import Interface + +class PrinterInterface(Interface): + _loop_delay = 30 + connection_type = 'printer' + + def get_devices(self): + printer_devices = {} + printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL) + + for printer in printers: + identifier = printer[2] + handle_printer = win32print.OpenPrinter(identifier) + win32print.GetPrinter(handle_printer, 2) + printer_devices[identifier] = { + 'identifier': identifier, + 'printer_handle': handle_printer, + } + return printer_devices diff --git a/addons/hw_drivers/iot_handlers/interfaces/SerialInterface.py b/addons/hw_drivers/iot_handlers/interfaces/SerialInterface.py index ae63969782f..d51e50fcdc8 100644 --- a/addons/hw_drivers/iot_handlers/interfaces/SerialInterface.py +++ b/addons/hw_drivers/iot_handlers/interfaces/SerialInterface.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from glob import glob +import serial.tools.list_ports from odoo.addons.hw_drivers.interface import Interface @@ -11,8 +11,8 @@ class SerialInterface(Interface): def get_devices(self): serial_devices = {} - for identifier in glob('/dev/serial/by-path/*'): - serial_devices[identifier] = { - 'identifier': identifier + for port in serial.tools.list_ports.comports(): + serial_devices[port.device] = { + 'identifier': port.device } return serial_devices diff --git a/addons/hw_drivers/iot_handlers/interfaces/USBInterface.py b/addons/hw_drivers/iot_handlers/interfaces/USBInterface_L.py similarity index 100% rename from addons/hw_drivers/iot_handlers/interfaces/USBInterface.py rename to addons/hw_drivers/iot_handlers/interfaces/USBInterface_L.py diff --git a/addons/hw_drivers/main.py b/addons/hw_drivers/main.py index 1503aa0ea99..8e4c46969c4 100644 --- a/addons/hw_drivers/main.py +++ b/addons/hw_drivers/main.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from traceback import format_exc - -from dbus.mainloop.glib import DBusGMainLoop import json +import platform import logging import socket from threading import Thread @@ -14,6 +13,12 @@ from odoo.addons.hw_drivers.tools import helpers _logger = logging.getLogger(__name__) +try: + from dbus.mainloop.glib import DBusGMainLoop +except ImportError: + DBusGMainLoop = None + _logger.error('Could not import library dbus') + drivers = [] interfaces = {} iot_devices = {} @@ -72,7 +77,9 @@ class Manager(Thread): Thread that will load interfaces and drivers and contact the odoo server with the updates """ - helpers.check_git_branch() + helpers.start_nginx_server() + if platform.system() == 'Linux': + helpers.check_git_branch() helpers.check_certificate() # We first add the IoT Box to the connected DB because IoT handlers cannot be downloaded if @@ -93,16 +100,16 @@ class Manager(Thread): while 1: try: if iot_devices != self.previous_iot_devices: - self.send_alldevices() self.previous_iot_devices = iot_devices.copy() + self.send_alldevices() time.sleep(3) except Exception: # No matter what goes wrong, the Manager loop needs to keep running _logger.error(format_exc()) - # Must be started from main thread -DBusGMainLoop(set_as_default=True) +if DBusGMainLoop: + DBusGMainLoop(set_as_default=True) manager = Manager() manager.daemon = True diff --git a/addons/hw_drivers/static/img/False.jpg b/addons/hw_drivers/static/img/False.jpg deleted file mode 100644 index 8f8e6489b30..00000000000 Binary files a/addons/hw_drivers/static/img/False.jpg and /dev/null differ diff --git a/addons/hw_drivers/static/img/True.jpg b/addons/hw_drivers/static/img/True.jpg deleted file mode 100644 index 0488574a699..00000000000 Binary files a/addons/hw_drivers/static/img/True.jpg and /dev/null differ diff --git a/addons/hw_drivers/tools/helpers.py b/addons/hw_drivers/tools/helpers.py index 5494bd0fe9c..7b11d62f717 100644 --- a/addons/hw_drivers/tools/helpers.py +++ b/addons/hw_drivers/tools/helpers.py @@ -3,6 +3,7 @@ import datetime from importlib import util +import platform import io import json import logging @@ -15,8 +16,9 @@ import urllib3 import zipfile from threading import Thread import time +import contextlib -from odoo import _, http +from odoo import _, http, service from odoo.tools.func import lazy_property from odoo.modules.module import get_resource_path @@ -36,14 +38,36 @@ class IoTRestart(Thread): def run(self): time.sleep(self.delay) - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + service.server.restart() + + +if platform.system() == 'Windows': + writable = contextlib.nullcontext +elif platform.system() == 'Linux': + @contextlib.contextmanager + def writable(): + subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) + subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/"]) + try: + yield + finally: + subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) + subprocess.call(["sudo", "mount", "-o", "remount,ro", "/root_bypass_ramdisks/"]) + subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) def access_point(): return get_ip() == '10.11.12.1' -def add_credential(db_uuid, enterprise_code): - write_file('odoo-db-uuid.conf', db_uuid) - write_file('odoo-enterprise-code.conf', enterprise_code) +def start_nginx_server(): + if platform.system() == 'Windows': + path_nginx = get_path_nginx() + if path_nginx: + os.chdir(path_nginx) + _logger.info('Start Nginx server: %s\\nginx.exe', path_nginx) + os.popen('nginx.exe') + os.chdir('..\\server') + elif platform.system() == 'Linux': + subprocess.check_call(["sudo", "service", "nginx", "restart"]) def check_certificate(): """ @@ -51,7 +75,10 @@ def check_certificate(): """ server = get_odoo_server_url() if server: - path = Path('/etc/ssl/certs/nginx-cert.crt') + if platform.system() == 'Windows': + path = Path(get_path_nginx()).joinpath('conf/nginx-cert.crt') + elif platform.system() == 'Linux': + path = Path('/etc/ssl/certs/nginx-cert.crt') if path.exists(): with path.open('r') as f: cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read()) @@ -94,14 +121,12 @@ def check_git_branch(): local_branch = subprocess.check_output(git + ['symbolic-ref', '-q', '--short', 'HEAD']).decode('utf-8').rstrip() if db_branch != local_branch: - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) - subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/drivers/*"]) - subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/interfaces/*"]) - subprocess.check_call(git + ['branch', '-m', db_branch]) - subprocess.check_call(git + ['remote', 'set-branches', 'origin', db_branch]) - os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh') - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) + with writable(): + subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/drivers/*"]) + subprocess.check_call(["rm", "-rf", "/home/pi/odoo/addons/hw_drivers/iot_handlers/interfaces/*"]) + subprocess.check_call(git + ['branch', '-m', db_branch]) + subprocess.check_call(git + ['remote', 'set-branches', 'origin', db_branch]) + os.system('/home/pi/odoo/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh') except Exception as e: _logger.error('Could not reach configured server') @@ -130,39 +155,37 @@ def check_image(): version = checkFile.get(valueLastest, 'Error').replace('iotboxv', '').replace('.zip', '').split('_') return {'major': version[0], 'minor': version[1]} +def save_conf_server(url, token, db_uuid, enterprise_code): + """ + Save config to connect IoT to the server + """ + write_file('odoo-remote-server.conf', url) + write_file('token', token) + write_file('odoo-db-uuid.conf', db_uuid or '') + write_file('odoo-enterprise-code.conf', enterprise_code or '') + def get_img_name(): major, minor = get_version().split('.') return 'iotboxv%s_%s.zip' % (major, minor) def get_ip(): - while True: - try: - return netifaces.ifaddresses('eth0')[netifaces.AF_INET][0]['addr'] - except KeyError: - pass - - try: - return netifaces.ifaddresses('wlan0')[netifaces.AF_INET][0]['addr'] - except KeyError: - pass - - _logger.warning("Couldn't get IP, sleeping and retrying.") - time.sleep(5) + interfaces = netifaces.interfaces() + for interface in interfaces: + if netifaces.ifaddresses(interface).get(netifaces.AF_INET): + addr = netifaces.ifaddresses(interface).get(netifaces.AF_INET)[0]['addr'] + if addr != '127.0.0.1': + return addr def get_mac_address(): - while True: - try: - return netifaces.ifaddresses('eth0')[netifaces.AF_LINK][0]['addr'] - except KeyError: - pass + interfaces = netifaces.interfaces() + for interface in interfaces: + if netifaces.ifaddresses(interface).get(netifaces.AF_INET): + addr = netifaces.ifaddresses(interface).get(netifaces.AF_LINK)[0]['addr'] + if addr != '00:00:00:00:00:00': + return addr - try: - return netifaces.ifaddresses('wlan0')[netifaces.AF_LINK][0]['addr'] - except KeyError: - pass - - _logger.warning("Couldn't get MAC address, sleeping and retrying.") - time.sleep(5) +def get_path_nginx(): + return str(list(Path().absolute().parent.glob('*nginx*'))[0]) def get_ssid(): ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive @@ -173,16 +196,20 @@ def get_ssid(): return subprocess.check_output(['sed', 's/.*"\\(.*\\)"/\\1/'], stdin=process_grep.stdout).decode('utf-8').rstrip() def get_odoo_server_url(): - ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive - if not ap: - return False + if platform.system() == 'Linux': + ap = subprocess.call(['systemctl', 'is-active', '--quiet', 'hostapd']) # if service is active return 0 else inactive + if not ap: + return False return read_file_first_line('odoo-remote-server.conf') def get_token(): return read_file_first_line('token') def get_version(): - return subprocess.check_output(['cat', '/var/odoo/iotbox_version']).decode().rstrip() + if platform.system() == 'Linux': + return read_file_first_line('/var/odoo/iotbox_version') + elif platform.system() == 'Windows': + return 'W22_11' def get_wifi_essid(): wifi_options = [] @@ -219,16 +246,17 @@ def load_certificate(): result = json.loads(response.data.decode('utf8'))['result'] if result: write_file('odoo-subject.conf', result['subject_cn']) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/"]) - Path('/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem']) - Path('/root_bypass_ramdisks/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem']) - Path('/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem']) - Path('/root_bypass_ramdisks/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem']) - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/root_bypass_ramdisks/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) - subprocess.check_call(["sudo", "service", "nginx", "restart"]) + if platform.system() == 'Linux': + with writable(): + Path('/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem']) + Path('/root_bypass_ramdisks/etc/ssl/certs/nginx-cert.crt').write_text(result['x509_pem']) + Path('/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem']) + Path('/root_bypass_ramdisks/etc/ssl/private/nginx-cert.key').write_text(result['private_key_pem']) + elif platform.system() == 'Windows': + Path(get_path_nginx()).joinpath('conf/nginx-cert.crt').write_text(result['x509_pem']) + Path(get_path_nginx()).joinpath('conf/nginx-cert.key').write_text(result['private_key_pem']) + time.sleep(3) + start_nginx_server() def download_iot_handlers(auto=True): """ @@ -240,14 +268,13 @@ def download_iot_handlers(auto=True): pm = urllib3.PoolManager(cert_reqs='CERT_NONE') server = server + '/iot/get_handlers' try: - resp = pm.request('POST', server, fields={'mac': get_mac_address(), 'auto': auto}) + resp = pm.request('POST', server, fields={'mac': get_mac_address(), 'auto': auto}, timeout=8) if resp.data: - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) - drivers_path = Path.home() / 'odoo/addons/hw_drivers/iot_handlers' - zip_file = zipfile.ZipFile(io.BytesIO(resp.data)) - zip_file.extractall(drivers_path) - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) + with writable(): + drivers_path = ['odoo', 'addons', 'hw_drivers', 'iot_handlers'] + path = path_file(str(Path().joinpath(*drivers_path))) + zip_file = zipfile.ZipFile(io.BytesIO(resp.data)) + zip_file.extractall(path) except Exception as e: _logger.error('Could not reach configured server') _logger.error('A error encountered : %s ' % e) @@ -260,38 +287,46 @@ def load_iot_handlers(): """ for directory in ['interfaces', 'drivers']: path = get_resource_path('hw_drivers', 'iot_handlers', directory) - filesList = os.listdir(path) + filesList = list_file_by_os(path) for file in filesList: - path_file = os.path.join(path, file) - spec = util.spec_from_file_location(file, path_file) + spec = util.spec_from_file_location(file, str(Path(path).joinpath(file))) if spec: module = util.module_from_spec(spec) spec.loader.exec_module(module) lazy_property.reset_all(http.root) +def list_file_by_os(file_list): + platform_os = platform.system() + if platform_os == 'Linux': + return [x.name for x in Path(file_list).glob('*[!W].*')] + elif platform_os == 'Windows': + return [x.name for x in Path(file_list).glob('*[!L].*')] + def odoo_restart(delay): IR = IoTRestart(delay) IR.start() +def path_file(filename): + platform_os = platform.system() + if platform_os == 'Linux': + return Path().absolute().parent.joinpath(filename) + elif platform_os == 'Windows': + return Path().absolute().parent.joinpath('server/' + filename) + def read_file_first_line(filename): - path = Path.home() / filename - path = Path('/home/pi/' + filename) + path = path_file(filename) if path.exists(): with path.open('r') as f: return f.readline().strip('\n') - return '' def unlink_file(filename): - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) - path = Path.home() / filename - if path.exists(): - path.unlink() - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) + with writable(): + path = path_file(filename) + if path.exists(): + path.unlink() -def write_file(filename, text): - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/"]) - path = Path.home() / filename - path.write_text(text) - subprocess.call(["sudo", "mount", "-o", "remount,ro", "/"]) - subprocess.call(["sudo", "mount", "-o", "remount,rw", "/root_bypass_ramdisks/etc/cups"]) +def write_file(filename, text, mode='w'): + with writable(): + path = path_file(filename) + with open(path, mode) as f: + f.write(text) diff --git a/addons/hw_l10n_eg_eta/__init__.py b/addons/hw_l10n_eg_eta/__init__.py deleted file mode 100644 index e046e49fbe2..00000000000 --- a/addons/hw_l10n_eg_eta/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import controllers diff --git a/addons/hw_l10n_eg_eta/__manifest__.py b/addons/hw_l10n_eg_eta/__manifest__.py deleted file mode 100644 index d9c1ac59978..00000000000 --- a/addons/hw_l10n_eg_eta/__manifest__.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -{ - 'name': 'Egypt ETA Hardware Driver', - 'category': 'Accounting/Accounting', - 'website': 'https://www.odoo.com', - 'summary': 'Egypt ETA Hardware Driver', - 'description': """ -Egypt ETA Hardware Driver -======================= - -This module allows Odoo to digitally sign invoices using an USB key approved by the egyptian government - -Special thanks to Plementus for their help in developing this module. - -Requirements per system ------------------------ - -Windows: - - eps2003csp11.dll - -Linux/macOS: - - OpenSC - -""", - 'external_dependencies': { - 'python': ['PyKCS11'], - }, - 'installable': False, - 'license': 'LGPL-3', -} diff --git a/addons/hw_l10n_eg_eta/controllers/__init__.py b/addons/hw_l10n_eg_eta/controllers/__init__.py deleted file mode 100644 index 12a7e529b67..00000000000 --- a/addons/hw_l10n_eg_eta/controllers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import main diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index f5571ac5e1a..9df22d675a9 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -1,7 +1,9 @@ +# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. import json import jinja2 +import platform import logging import os from pathlib import Path @@ -10,10 +12,10 @@ import subprocess import sys import threading -from odoo import http +from odoo import http, service from odoo.http import Response from odoo.modules.module import get_resource_path - +from odoo.addons.hw_drivers.connection_manager import connection_manager from odoo.addons.hw_drivers.main import iot_devices from odoo.addons.hw_drivers.tools import helpers from odoo.addons.web.controllers.home import Home @@ -59,8 +61,11 @@ class IoTboxHomepage(Home): def get_homepage_data(self): hostname = str(socket.gethostname()) - ssid = helpers.get_ssid() - wired = subprocess.check_output(['cat', '/sys/class/net/eth0/operstate']).decode('utf-8').strip('\n') + if platform.system() == 'Linux': + ssid = helpers.get_ssid() + wired = helpers.read_file_first_line('/sys/class/net/eth0/operstate') + else: + wired = 'up' if wired == 'up': network = 'Ethernet' elif ssid: @@ -85,9 +90,11 @@ class IoTboxHomepage(Home): 'mac': helpers.get_mac_address(), 'iot_device_status': iot_device, 'server_status': helpers.get_odoo_server_url() or 'Not Configured', + 'pairing_code': connection_manager.pairing_code, 'six_terminal': self.get_six_terminal(), 'network_status': network, 'version': helpers.get_version(), + 'system': platform.system(), } @http.route('/', type='http', auth='none') @@ -101,14 +108,8 @@ class IoTboxHomepage(Home): @http.route('/list_handlers', type='http', auth='none', website=True) def list_handlers(self): - drivers_list = [] - for driver in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/drivers')): - if driver != '__pycache__': - drivers_list.append(driver) - interfaces_list = [] - for interface in os.listdir(get_resource_path('hw_drivers', 'iot_handlers/interfaces')): - if interface != '__pycache__': - interfaces_list.append(interface) + drivers_list = helpers.list_file_by_os(get_resource_path('hw_drivers', 'iot_handlers', 'drivers')) + interfaces_list = helpers.list_file_by_os(get_resource_path('hw_drivers', 'iot_handlers', 'interfaces')) return handler_list_template.render({ 'title': "Odoo's IoT Box - Handlers list", 'breadcrumb': 'Handlers list', @@ -120,7 +121,7 @@ class IoTboxHomepage(Home): @http.route('/load_iot_handlers', type='http', auth='none', website=True) def load_iot_handlers(self): helpers.download_iot_handlers(False) - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + helpers.odoo_restart(0) return "" @http.route('/list_credential', type='http', auth='none', website=True) @@ -134,15 +135,16 @@ class IoTboxHomepage(Home): @http.route('/save_credential', type='http', auth='none', cors='*', csrf=False) def save_credential(self, db_uuid, enterprise_code): - helpers.add_credential(db_uuid, enterprise_code) - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + helpers.write_file('odoo-db-uuid.conf', db_uuid) + helpers.write_file('odoo-enterprise-code.conf', enterprise_code) + helpers.odoo_restart(0) return "" @http.route('/clear_credential', type='http', auth='none', cors='*', csrf=False) def clear_credential(self): helpers.unlink_file('odoo-db-uuid.conf') helpers.unlink_file('odoo-enterprise-code.conf') - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + helpers.odoo_restart(0) return "" @http.route('/wifi', type='http', auth='none', website=True) @@ -192,9 +194,9 @@ class IoTboxHomepage(Home): @http.route('/handlers_clear', type='http', auth='none', cors='*', csrf=False) def clear_handlers_list(self): for directory in ['drivers', 'interfaces']: - for file in os.listdir(get_resource_path('hw_drivers', 'iot_handlers', directory)): - if file != '__pycache__': - helpers.unlink_file(get_resource_path('hw_drivers', 'iot_handlers', directory, file)) + for file in list(Path(get_resource_path('hw_drivers', 'iot_handlers', directory)).glob('*')): + if file.name != '__pycache__': + helpers.unlink_file(str(file.relative_to(*file.parts[:3]))) return "" @http.route('/server_connect', type='http', auth='none', cors='*', csrf=False) @@ -203,16 +205,16 @@ class IoTboxHomepage(Home): credential = token.split('|') url = credential[0] token = credential[1] - if len(credential) > 2: - # IoT Box send token with db_uuid and enterprise_code only since V13 - db_uuid = credential[2] - enterprise_code = credential[3] - helpers.add_credential(db_uuid, enterprise_code) + db_uuid = credential[2] + enterprise_code = credential[3] + helpers.save_conf_server(url, token, db_uuid, enterprise_code) else: url = helpers.get_odoo_server_url() token = helpers.get_token() - reboot = 'reboot' - subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/connect_to_server.sh'), url, iotname, token, reboot]) + if iotname: + subprocess.check_call([get_resource_path('point_of_sale', 'tools/posbox/configuration/rename_iot.sh'), iotname]) + else: + helpers.odoo_restart(3) return 'http://' + helpers.get_ip() + ':8069' @http.route('/steps', type='http', auth='none', cors='*', csrf=False) @@ -280,13 +282,13 @@ class IoTboxHomepage(Home): @http.route('/six_payment_terminal_add', type='http', auth='none', cors='*', csrf=False) def add_six_payment_terminal(self, terminal_id): helpers.write_file('odoo-six-payment-terminal.conf', terminal_id) - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + service.server.restart() return 'http://' + helpers.get_ip() + ':8069' @http.route('/six_payment_terminal_clear', type='http', auth='none', cors='*', csrf=False) def clear_six_payment_terminal(self): helpers.unlink_file('odoo-six-payment-terminal.conf') - subprocess.check_call(["sudo", "service", "odoo", "restart"]) + service.server.restart() return "" @http.route('/hw_proxy/upgrade', type='http', auth='none', ) diff --git a/addons/hw_posbox_homepage/views/homepage.html b/addons/hw_posbox_homepage/views/homepage.html index d116b5cd4de..876b7ee3ed6 100644 --- a/addons/hw_posbox_homepage/views/homepage.html +++ b/addons/hw_posbox_homepage/views/homepage.html @@ -155,7 +155,9 @@
Restart
- + {% if system == "Linux" %} + + {% endif %}
@@ -165,11 +167,11 @@ - + - + @@ -181,7 +183,7 @@ - + @@ -193,6 +195,12 @@ {% endif %} + {% if pairing_code %} + + + + + {% endif %}
Name {{ hostname }} configure {{ hostname }} {% if system == "Linux" %}configure{% endif %}
Version {{ version }} update {{ version }} {% if system == "Linux" %}update{% endif %}
IP Address
Network{{ network_status }} configure wifi{{ network_status }} {% if system == "Linux" %}configure wifi{% endif %}
Server{{ six_terminal }} configure
Pairing code{{ pairing_code }}
IOT Device @@ -220,8 +228,10 @@
POS Display - Remote Debug - Printers server + {% if system == "Linux" %} + Remote Debug + Printers server + {% endif %} {% if server_status != "Not Configured" %} Credential {% endif %} diff --git a/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh b/addons/point_of_sale/tools/posbox/configuration/rename_iot.sh old mode 100755 new mode 100644 similarity index 72% rename from addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh rename to addons/point_of_sale/tools/posbox/configuration/rename_iot.sh index 3c6e8be534f..eeec51f28ad --- a/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh +++ b/addons/point_of_sale/tools/posbox/configuration/rename_iot.sh @@ -2,15 +2,10 @@ # Write the server configuration function connect () { - SERVER="${1}" - CURRENT_SERVER_FILE=/home/pi/odoo-remote-server.conf - TOKEN_FILE=/home/pi/token - TOKEN="${3}" - REBOOT="${4}" HOSTS=/root_bypass_ramdisks/etc/hosts HOST_FILE=/root_bypass_ramdisks/etc/hostname HOSTNAME="$(hostname)" - IOT_NAME="${2}" + IOT_NAME="${1}" IOT_NAME="${IOT_NAME//[^[:ascii:]]/}" IOT_NAME="${IOT_NAME//[^a-zA-Z0-9-]/}" if [ -z "$IOT_NAME" ] @@ -19,11 +14,6 @@ function connect () { fi sudo mount -o remount,rw / sudo mount -o remount,rw /root_bypass_ramdisks - if [ ! -z "${1}" ] - then - echo "${SERVER}" > ${CURRENT_SERVER_FILE} - echo "${TOKEN}" > ${TOKEN_FILE} - fi if [ "${IOT_NAME}" != "${HOSTNAME}" ] then sudo sed -i "s/${HOSTNAME}/${IOT_NAME}/g" ${HOSTS} @@ -39,10 +29,6 @@ function connect () { fi sudo mount -o remount,ro / sudo mount -o remount,ro /root_bypass_ramdisks - if [ "$REBOOT" == 'reboot' ] - then - sudo service odoo restart - fi } -connect "${1}" "${2}" "${3}" "${4}" \ No newline at end of file +connect "${1}" diff --git a/addons/point_of_sale/tools/posbox/posbox_create_image.sh b/addons/point_of_sale/tools/posbox/posbox_create_image.sh index 565e347ba04..2c4c746b4f2 100755 --- a/addons/point_of_sale/tools/posbox/posbox_create_image.sh +++ b/addons/point_of_sale/tools/posbox/posbox_create_image.sh @@ -28,8 +28,8 @@ __base="$(basename ${__file} .sh)" MOUNT_POINT="${__dir}/root_mount" OVERWRITE_FILES_BEFORE_INIT_DIR="${__dir}/overwrite_before_init" OVERWRITE_FILES_AFTER_INIT_DIR="${__dir}/overwrite_after_init" -VERSION=15.0 -VERSION_IOTBOX=21.10 +VERSION=16.0 +VERSION_IOTBOX=22.11 REPO=https://github.com/odoo/odoo.git if ! file_exists *raspios*.img ; then diff --git a/setup/win32/Makefile b/setup/win32/Makefile index b1c1e6d6d58..526b3555f75 100644 --- a/setup/win32/Makefile +++ b/setup/win32/Makefile @@ -26,15 +26,18 @@ server_clean: rm -rf $(SERVER_DIRECTORY)/.cyg* allinone: server_clean +# need to install requirements-local-proxy.txt for local proxy install cp $(SERVER_DIRECTORY)/requirements.txt $(WINPY32_DIR)/ + cp requirements-local-proxy.txt $(WINPY32_DIR)/ -(cd $(WINPY32_DIR) && ./python.exe -m pip install --upgrade pip) - -(cd $(WINPY32_DIR) && cat requirements.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done) - -(cd $(WINPY32_DIR) && Scripts/pip3.exe freeze) + -(cd $(WINPY32_DIR) && cat requirements*.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done) + -(cd $(WINPY32_DIR) && Scripts/pip3.exe list) rm $(WINPY32_DIR)/requirements.txt cp $(SERVER_DIRECTORY)/requirements.txt $(WINPY64_DIR)/ + cp requirements-local-proxy.txt $(WINPY64_DIR)/ -(cd $(WINPY64_DIR) && ./python.exe -m pip install --upgrade pip) - -(cd $(WINPY64_DIR) && cat requirements.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done) - -(cd $(WINPY64_DIR) && Scripts/pip3.exe freeze) + -(cd $(WINPY64_DIR) && cat requirements*.txt | while read PAC ; do Scripts/pip3.exe install "$${PAC%%#*}" ; done) + -(cd $(WINPY64_DIR) && Scripts/pip3.exe list) rm $(WINPY64_DIR)/requirements.txt (cd $(SERVER_DIRECTORY)/setup/win32 && $(LAUNCH_MAKENSIS)) (cd $(SERVER_DIRECTORY)/setup/win32 && mkdir -p $(FILES_DIRECTORY)) diff --git a/setup/win32/conf/nginx/nginx.conf b/setup/win32/conf/nginx/nginx.conf new file mode 100644 index 00000000000..a039c819226 --- /dev/null +++ b/setup/win32/conf/nginx/nginx.conf @@ -0,0 +1,19 @@ +events { + worker_connections 1024; +} + +http { + server { + listen 443 ssl http2 default_server; + listen [::]:443 ssl http2 default_server; + server_name localhost; + ssl_certificate nginx-cert.crt; + ssl_certificate_key nginx-cert.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { + proxy_read_timeout 600s; + proxy_pass http://127.0.0.1:8069; + } + } +} diff --git a/setup/win32/requirements-local-proxy.txt b/setup/win32/requirements-local-proxy.txt new file mode 100644 index 00000000000..7f8cf902ce7 --- /dev/null +++ b/setup/win32/requirements-local-proxy.txt @@ -0,0 +1,3 @@ +netifaces==0.11.0 +PyKCS11==1.5.10 +ghostscript==0.7 diff --git a/setup/win32/setup.nsi b/setup/win32/setup.nsi index 13dc3ba9417..20c2d93905c 100644 --- a/setup/win32/setup.nsi +++ b/setup/win32/setup.nsi @@ -174,10 +174,12 @@ LangString DESC_PostgreSQL_Username ${LANG_ENGLISH} "Username" LangString DESC_PostgreSQL_Password ${LANG_ENGLISH} "Password" LangString Profile_AllInOne ${LANG_ENGLISH} "Odoo Server And PostgreSQL Server" LangString Profile_Server ${LANG_ENGLISH} "Odoo Server Only" -LangString Profile_LocalProxyMode ${LANG_ENGLISH} "Local Proxy Mode" +LangString Profile_IOT ${LANG_ENGLISH} "Odoo IoT" LangString TITLE_Odoo_Server ${LANG_ENGLISH} "Odoo Server" LangString TITLE_PostgreSQL ${LANG_ENGLISH} "PostgreSQL Database" -LangString TITLE_LocalProxyMode ${LANG_ENGLISH} "Local Proxy Mode" +LangString TITLE_IOT ${LANG_ENGLISH} "Odoo IoT" +LangString TITLE_Nginx ${LANG_ENGLISH} "Nginx WebServer" +LangString TITLE_Ghostscript ${LANG_ENGLISH} "Ghostscript interpreter" LangString DESC_FinishPageText ${LANG_ENGLISH} "Start Odoo" ; French @@ -197,16 +199,18 @@ LangString DESC_PostgreSQL_Username ${LANG_FRENCH} "Utilisateur" LangString DESC_PostgreSQL_Password ${LANG_FRENCH} "Mot de passe" LangString Profile_AllInOne ${LANG_FRENCH} "Serveur Odoo Et Serveur PostgreSQL" LangString Profile_Server ${LANG_FRENCH} "Seulement Le Serveur Odoo" -LangString Profile_LocalProxyMode ${LANG_FRENCH} "Mode Proxy Local" +LangString Profile_IOT ${LANG_FRENCH} "Odoo IoT" LangString TITLE_Odoo_Server ${LANG_FRENCH} "Serveur Odoo" LangString TITLE_PostgreSQL ${LANG_FRENCH} "Installation du serveur de base de données PostgreSQL" -LangString TITLE_LocalProxyMode ${LANG_FRENCH} "Mode Proxy Local" +LangString TITLE_IOT ${LANG_FRENCH} "Odoo IoT" +LangString TITLE_Nginx ${LANG_FRENCH} "Installation du serveur web Nginx" +LangString TITLE_Ghostscript ${LANG_FRENCH} "Installation de l'interpréteur Ghostscript" LangString DESC_FinishPageText ${LANG_FRENCH} "Démarrer Odoo" InstType /NOCUSTOM InstType $(Profile_AllInOne) InstType $(Profile_Server) -InstType $(Profile_LocalProxyMode) +InstType $(Profile_IOT) Section $(TITLE_Odoo_Server) SectionOdoo_Server SectionIn 1 2 3 @@ -247,6 +251,8 @@ Section $(TITLE_Odoo_Server) SectionOdoo_Server # Fix the addons path WriteIniStr "$INSTDIR\server\odoo.conf" "options" "addons_path" "$INSTDIR\server\odoo\addons" WriteIniStr "$INSTDIR\server\odoo.conf" "options" "bin_path" "$INSTDIR\thirdparty" + # Set data_dir + WriteIniStr "$INSTDIR\server\odoo.conf" "options" "data_dir" "$INSTDIR\sessions" # if we're going to install postgresql force it's path, # otherwise we consider it's always done and/or correctly tune by users @@ -256,17 +262,18 @@ Section $(TITLE_Odoo_Server) SectionOdoo_Server # Productivity Apps WriteIniStr "$INSTDIR\server\odoo.conf" "options" "default_productivity_apps" "True" - DetailPrint "Installing Windows service" nsExec::ExecTOLog '"$INSTDIR\python\python.exe" "$INSTDIR\server\odoo-bin" --stop-after-init --logfile "$INSTDIR\server\odoo.log" -s' ${If} ${RunningX64} nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" install ${SERVICENAME} "$INSTDIR\python\python.exe"' nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} AppDirectory "$\"$INSTDIR\python$\""' nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} AppParameters "\"$INSTDIR\server\odoo-bin\" -c "\"$INSTDIR\server\odoo.conf\"' + nsExec::ExecToLog '"$INSTDIR\nssm\win64\nssm.exe" set ${SERVICENAME} ObjectName "SERVICE LOCAL" ""' ${Else} nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" install ${SERVICENAME} "$INSTDIR\python\python.exe" ' nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} AppDirectory "$\"$INSTDIR\python$\""' nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} AppParameters "\"$INSTDIR\server\odoo-bin\" -c "\"$INSTDIR\server\odoo.conf\"' + nsExec::ExecToLog '"$INSTDIR\nssm\win32\nssm.exe" set ${SERVICENAME} ObjectName "SERVICE LOCAL" ""' ${EndIf} Call RestartOdooService @@ -309,18 +316,73 @@ Section $(TITLE_PostgreSQL) SectionPostgreSQL --serverport $TextPostgreSQLPort' SectionEnd -Section $(TITLE_LocalProxyMode) LocalProxy +Section $(TITLE_IOT) IOT SectionIn 3 - DetailPrint "Configuring Local Proxy Mode" - WriteIniStr "$INSTDIR\server\odoo.conf" "options" "server_wide_modules" "base,web,hw_l10n_eg_eta" + DetailPrint "Configuring TITLE_IOT" + WriteIniStr "$INSTDIR\server\odoo.conf" "options" "server_wide_modules" "web,hw_posbox_homepage,hw_drivers" WriteIniStr "$INSTDIR\server\odoo.conf" "options" "list_db" "False" - WriteIniStr "$INSTDIR\server\odoo.conf" "options" "max_cron_thread" "0" + WriteIniStr "$INSTDIR\server\odoo.conf" "options" "max_cron_threads" "0" nsExec::ExecToStack '"$INSTDIR\python\python.exe" "$INSTDIR\server\odoo-bin" genproxytoken' pop $0 pop $ProxyTokenPwd Call RestartOdooService SectionEnd + +Section $(TITLE_Nginx) Nginx + SectionIn 3 + SetOutPath '$TEMP' + VAR /GLOBAL nginx_zip_filename + VAR /GLOBAL nginx_url + + # need unzip plugin: + # https://nsis.sourceforge.io/mediawiki/images/5/5a/NSISunzU.zip + StrCpy $nginx_zip_filename "nginx-1.22.0.zip" + StrCpy $nginx_url "https://nginx.org/download/$nginx_zip_filename" + + DetailPrint "Downloading Nginx" + inetc::get "$nginx_url" "$TEMP\$nginx_zip_filename" /POPUP + DetailPrint "Temp dir: $TEMP\$nginx_zip_filename" + DetailPrint "Unzip Nginx" + nsisunz::UnzipToLog "$TEMP\$nginx_zip_filename" "$INSTDIR" + + Pop $0 + StrCmp $0 "success" ok + DetailPrint "$0" ;print error message to log + ok: + + FindFirst $0 $1 "$INSTDIR\nginx*" + DetailPrint "Setting up nginx" + SetOutPath "$INSTDIR\$1\conf" + CreateDirectory $INSTDIR\$1\temp + CreateDirectory $INSTDIR\$1\logs + FindClose $0 + File "conf\nginx\nginx.conf" + # Temporary certs for the first start + File "..\..\odoo\addons\point_of_sale\tools\posbox\overwrite_after_init\etc\ssl\certs\nginx-cert.crt" + File "..\..\odoo\addons\point_of_sale\tools\posbox\overwrite_after_init\etc\ssl\private\nginx-cert.key" +SectionEnd + +Section $(TITLE_Ghostscript) SectionGhostscript + SectionIn 3 + SetOutPath '$TEMP' + VAR /GLOBAL ghostscript_exe_filename + VAR /GLOBAL ghostscript_url + + StrCpy $ghostscript_exe_filename "gs1000w64.exe" + StrCpy $ghostscript_url "https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs1000/$ghostscript_exe_filename" + + DetailPrint "Downloading Ghostscript" + inetc::get "$ghostscript_url" "$TEMP\$ghostscript_exe_filename" /POPUP + DetailPrint "Temp dir: $TEMP\$ghostscript_exe_filename" + + Rmdir /r "INSTDIR\Ghostscript" + DetailPrint "Installing Ghostscript" + ExecWait '"$TEMP\$ghostscript_exe_filename" \ + /S \ + /D=$INSTDIR\Ghostscript' +SectionEnd + Section -Post WriteRegExpandStr HKLM "${UNINSTALL_REGISTRY_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe" WriteRegExpandStr HKLM "${UNINSTALL_REGISTRY_KEY}" "InstallLocation" "$INSTDIR" @@ -347,15 +409,20 @@ Section "Uninstall" Pop $R0 ReadRegStr $0 HKLM "${UNINSTALL_REGISTRY_KEY_SERVER}" "UninstallString" ExecWait '"$0" /S' + ExecWait '"$INSTDIR\Ghostscript\uninstgs.exe" /S' nsExec::Exec "net stop ${SERVICENAME}" nsExec::Exec "sc delete ${SERVICENAME}" sleep 2 Rmdir /r "$INSTDIR\server" + Rmdir /r "$INSTDIR\sessions" Rmdir /r "$INSTDIR\thirdparty" Rmdir /r "$INSTDIR\python" Rmdir /r "$INSTDIR\nssm" + FindFirst $0 $1 "$INSTDIR\nginx*" + Rmdir /R "$INSTDIR\$1" + FindClose $0 DeleteRegKey HKLM "${UNINSTALL_REGISTRY_KEY}" SectionEnd @@ -503,7 +570,7 @@ Function ShowProxyTokenDialogPage Abort ${EndIf} - ${NSD_CreateLabel} 0 0 100% 25% "Here is your access token for the Odoo Local Proxy, please write it down in a safe place, you will need it to configure the proxy" + ${NSD_CreateLabel} 0 0 100% 25% "Here is your access token for the Odoo IOT, please write it down in a safe place, you will need it to configure the IOT" Pop $ProxyTokenLabel ${NSD_CreateText} 0 30% 100% 13u $ProxyTokenPwd