diff --git a/.gitignore b/.gitignore index f9db17e..2bf95fd 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,3 @@ requirements.txt requirement/ignore_requirements.txt screenshots screencasts -script/todo/todo_override.json diff --git a/conf/make.docker.Makefile b/conf/make.docker.Makefile index cd1750f..f421029 100644 --- a/conf/make.docker.Makefile +++ b/conf/make.docker.Makefile @@ -53,14 +53,26 @@ docker_exec_erplibre_repo_show_status: docker_build_odoo_16: ./script/docker/docker_build.sh --odoo_16 +.PHONY: docker_build_odoo_16_clean +docker_build_odoo_16_clean: + ./script/docker/docker_build.sh --odoo_16 --no-cache + .PHONY: docker_build_odoo_14 docker_build_odoo_14: ./script/docker/docker_build.sh --odoo_14 +.PHONY: docker_build_odoo_14_clean +docker_build_odoo_14_clean: + ./script/docker/docker_build.sh --odoo_14 --no-cache + .PHONY: docker_build_odoo_12 docker_build_odoo_12: ./script/docker/docker_build.sh --odoo_12 +.PHONY: docker_build_odoo_12_clean +docker_build_odoo_12_clean: + ./script/docker/docker_build.sh --odoo_12 --no-cache + # build docker release .PHONY: docker_build_release docker_build_release: diff --git a/doc/FAQ.md b/doc/FAQ.md index 65a51f3..a950c05 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -221,3 +221,9 @@ cat /proc/sys/fs/inotify/max_user_watches Tips, when doing `sudo sysctl -p --system`, validate the order of the process, another process can overwrite your new value. + +## How killing all process from selenium + +```bash +pkill -f "firefox.*--marionette" +``` diff --git a/docker/docker-compose_odoo_12.0.yml b/docker/docker-compose_odoo_12.0.yml index dcdaccb..2e58086 100644 --- a/docker/docker-compose_odoo_12.0.yml +++ b/docker/docker-compose_odoo_12.0.yml @@ -27,6 +27,7 @@ services: # See the volume section at the end of the file - erplibre_data_dir:/home/odoo/.local/share/Odoo - ./addons/addons:/ERPLibre/addons/addons + - ./private:/ERPLibre/private - erplibre_conf:/etc/odoo restart: always diff --git a/docker/docker-compose_odoo_14.0.yml b/docker/docker-compose_odoo_14.0.yml index a36b178..cb67650 100644 --- a/docker/docker-compose_odoo_14.0.yml +++ b/docker/docker-compose_odoo_14.0.yml @@ -1,7 +1,7 @@ version: "3.3" services: ERPLibre: - image: technolibre/erplibre:1.6.0_odoo_14.0_2a8af84 + image: technolibre/erplibre:1.6.0_odoo_14.0_1890768 ports: - 8069:8069 - 8071:8071 @@ -27,6 +27,7 @@ services: # See the volume section at the end of the file - erplibre_data_dir:/home/odoo/.local/share/Odoo - ./addons/addons:/ERPLibre/addons/addons + - ./private:/ERPLibre/private - erplibre_conf:/etc/odoo restart: always diff --git a/docker/docker-compose_odoo_16.0.yml b/docker/docker-compose_odoo_16.0.yml index adf1c55..7ffd6be 100644 --- a/docker/docker-compose_odoo_16.0.yml +++ b/docker/docker-compose_odoo_16.0.yml @@ -27,6 +27,7 @@ services: # See the volume section at the end of the file - erplibre_data_dir:/home/odoo/.local/share/Odoo - ./addons/addons:/ERPLibre/addons/addons + - ./private:/ERPLibre/private - erplibre_conf:/etc/odoo restart: always diff --git a/manifest/default.dev.odoo16.0.xml b/manifest/default.dev.odoo16.0.xml index b47ea74..615856b 100644 --- a/manifest/default.dev.odoo16.0.xml +++ b/manifest/default.dev.odoo16.0.xml @@ -97,7 +97,7 @@ - + @@ -107,20 +107,20 @@ - + - + - + - - + + - + @@ -129,7 +129,7 @@ - + diff --git a/private/TODO.md b/private/TODO.md new file mode 100644 index 0000000..068db6f --- /dev/null +++ b/private/TODO.md @@ -0,0 +1 @@ +Move your private file and project configuration here. The docker will share a volume with this repertory. diff --git a/private/__init__.py b/private/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/script/selenium/selenium_lib.py b/script/selenium/selenium_lib.py index c488f69..d802867 100644 --- a/script/selenium/selenium_lib.py +++ b/script/selenium/selenium_lib.py @@ -8,7 +8,13 @@ import random import re import sys import time +import json +import tempfile from subprocess import getoutput +import tkinter as tk +from tkinter import filedialog +import getpass +from pykeepass import PyKeePass from randomwordfr import RandomWordFr from selenium import webdriver @@ -20,16 +26,24 @@ from selenium.webdriver import ActionChains from selenium.webdriver.common.actions.wheel_input import ScrollOrigin from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys +from selenium.webdriver.firefox.options import Options from selenium.webdriver.firefox.service import Service from selenium.webdriver.remote.webelement import WebElement from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait +# TODO maybe use TODO lib +CONFIG_FILE = "./script/todo/todo.json" +CONFIG_OVERRIDE_FILE = "./private/todo.json" +LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt" + class SeleniumLib(object): def __init__(self, config): self.config = config + self.kdbx = None self.video_recorder = None + self.default_download_dir_path = tempfile.mkdtemp() if self.config.video_suffix: self.filename_recording = ( f"video_{self.config.video_suffix}_" @@ -67,6 +81,9 @@ class SeleniumLib(object): if not self.config.not_private_mode: firefox_options.add_argument("--private") + if self.config.headless: + firefox_options.add_argument("--headless") + # firefox_options.set_preference("browser.link.open_newwindow", 3) # firefox_options.set_preference("browser.link.open_newwindow.restriction", 2) @@ -75,6 +92,18 @@ class SeleniumLib(object): firefox_options.set_preference( "permissions.default.desktop-notification", 1 ) + firefox_options.set_preference("browser.download.folderList", 2) + firefox_options.set_preference( + "browser.download.manager.showWhenStarting", False + ) + firefox_options.set_preference( + "browser.download.dir", self.default_download_dir_path + ) + firefox_options.set_preference( + "browser.helperApps.neverAsk.saveToDisk", + "application/octet-stream,application/pdf,application/x-pdf", + ) + firefox_options.set_preference("pdfjs.disabled", True) firefox_services = None if self.config.firefox_binary_path: firefox_services = Service( @@ -182,6 +211,53 @@ class SeleniumLib(object): self.driver.close() self.driver.switch_to.window(self.driver.window_handles[0]) + def get_kdbx(self): + if self.kdbx: + return self.kdbx + # Open file + chemin_fichier_kdbx = self.get_config(["kdbx", "path"]) + if not chemin_fichier_kdbx: + root = tk.Tk() + root.withdraw() # Hide the main window + chemin_fichier_kdbx = filedialog.askopenfilename( + title="Select a File", + filetypes=(("KeepassX files", "*.kdbx"),), + ) + if not chemin_fichier_kdbx: + # _logger.error(f"KDBX is not configured, please fill {CONFIG_FILE}") + return + + mot_de_passe_kdbx = self.get_config(["kdbx", "password"]) + if not mot_de_passe_kdbx: + mot_de_passe_kdbx = getpass.getpass( + prompt="Entrez votre mot de passe : " + ) + + kp = PyKeePass(chemin_fichier_kdbx, password=mot_de_passe_kdbx) + + if kp: + self.kdbx = kp + return kp + + def get_config(self, lst_params): + # Open file + config_file = CONFIG_FILE + if os.path.exists(CONFIG_OVERRIDE_FILE): + config_file = CONFIG_OVERRIDE_FILE + + with open(config_file) as cfg: + dct_data = json.load(cfg) + for param in lst_params: + try: + dct_data = dct_data[param] + except KeyError: + # _logger.error( + # f"KeyError on file {config_file} with keys" + # f" {lst_params}" + # ) + return + return dct_data + @staticmethod def get_french_word_no_space_no_accent(): word = "" @@ -248,6 +324,12 @@ class SeleniumLib(object): return ele + def get_text_from_element( + self, by: str = By.ID, value: str = None, timeout=5 + ): + ele = self.get_element(by, value, timeout=timeout) + return ele.text + def get_all_element(self, by: str = By.ID, value: str = None, timeout=5): wait = WebDriverWait(self.driver, timeout) ele = wait.until( @@ -1133,6 +1215,11 @@ def fill_parser(parser): action="store_true", help="Default is private mode.", ) + group_browser.add_argument( + "--headless", + action="store_true", + help="For automation without GUI.", + ) group_browser.add_argument( "--no_dark_mode", action="store_true", diff --git a/script/todo/README.md b/script/todo/README.md index 983796d..245167c 100644 --- a/script/todo/README.md +++ b/script/todo/README.md @@ -1,4 +1,4 @@ TODO is an assistant robot to use ERPLibre Execute it with `./script/todo/todo.py` or `make todo`. -For a new project, copy todo_example.json to todo_override.json and edit it. +For a new project, copy todo_example.json to private/todo.json and edit it. diff --git a/script/todo/todo.py b/script/todo/todo.py index de1c700..b78b87a 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -87,7 +87,7 @@ except ModuleNotFoundError as e: _logger = logging.getLogger(__name__) CONFIG_FILE = "./script/todo/todo.json" -CONFIG_OVERRIDE_FILE = "./script/todo/todo_override.json" +CONFIG_OVERRIDE_FILE = "./private/todo.json" LOGO_ASCII_FILE = "./script/todo/logo_ascii.txt"