From a090022ebcc1884ba13bbf71741bed0c8b0a7025 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Wed, 4 Oct 2023 10:44:18 +0200 Subject: [PATCH] [MIG] shopinvader_search_engine_image: Migration from 14.0 To improve naming consistency the original shopinvader_image addon is renamed shopinvader_search_engine_image --- .pre-commit-config.yaml | 1 - .../addons/shopinvader_search_engine_image | 1 + .../shopinvader_search_engine_product_image | 1 + .../shopinvader_search_engine_image/setup.py | 6 + shopinvader_image/__init__.py | 2 - shopinvader_image/__manifest__.py | 28 - shopinvader_image/data/ir_export_category.xml | 9 - shopinvader_image/data/ir_export_product.xml | 9 - shopinvader_image/demo/backend_demo.xml | 15 - .../demo/product_image_relation_demo.xml | 593 --------- shopinvader_image/demo/storage_file_demo.xml | 567 --------- shopinvader_image/demo/storage_image_demo.xml | 322 ----- shopinvader_image/hooks.py | 68 -- shopinvader_image/i18n/shopinvader_image.pot | 186 --- shopinvader_image/models/__init__.py | 5 - .../models/shopinvader_backend.py | 46 - .../models/shopinvader_category.py | 12 - .../models/shopinvader_image_mixin.py | 132 -- .../models/shopinvader_image_resize.py | 22 - .../models/shopinvader_variant.py | 11 - shopinvader_image/readme/DESCRIPTION.rst | 2 - shopinvader_image/readme/INSTALL.rst | 1 - shopinvader_image/readme/USAGE.rst | 4 - .../security/ir.model.access.csv | 3 - shopinvader_image/tests/__init__.py | 2 - shopinvader_image/tests/common.py | 32 - shopinvader_image/tests/test_cart.py | 11 - shopinvader_image/tests/test_images.py | 130 -- .../views/shopinvader_backend_view.xml | 24 - .../views/shopinvader_image_resize_view.xml | 54 - .../README.rst | 0 shopinvader_search_engine_image/__init__.py | 2 + .../__manifest__.py | 28 + .../demo/fs_product_image.xml | 1057 +++++++++++++++++ .../demo/image_tag.xml | 0 .../demo/se_thumbnail_size.xml | 6 +- .../models/__init__.py | 1 + .../models/se_backend.py | 80 ++ .../readme/CONTRIBUTORS.rst | 0 .../readme/DESCRIPTION.rst | 4 + .../readme/HISTORY.rst | 0 .../readme/USAGE.rst | 3 + .../readme/newsfragments/.gitignore | 0 .../schemas/__init__.py | 4 + .../schemas/image_data.py | 11 + .../schemas/images_mixin.py | 86 ++ .../schemas/product_category.py | 14 + .../schemas/product_product.py | 14 + .../static/description/index.html | 0 ...uk_thelma_dining_chairs_oak_grey07-524.jpg | Bin .../static/img/51gnjksrxml_sl1024_-497.jpg | Bin ...uk_thelma_dining_chairs_oak_grey02-515.jpg | Bin .../static/img/61kcwirwmjl_sl1500_-289.jpg | Bin .../static/img/61ncsqkegrl_sl1500_-298.jpg | Bin .../static/img/61vffbcilbl_sl1500_-292.jpg | Bin .../static/img/61vvazh7fbl_sl1500_-295.jpg | Bin .../static/img/71c62lnhnxl_sx522_-2.jpg | Bin .../static/img/71ezvti-0l_sx522_-32.jpg | Bin .../static/img/71fudutmpl_sl1500_-310.jpg | Bin .../static/img/71guazzso7l_sl1500_-50.jpg | Bin .../static/img/71gulsoprfl_sl1500_-53.jpg | Bin .../static/img/71qy77hpsgl_sx522_-35.jpg | Bin .../static/img/71r0tdtl1sl_sl1500_-304.jpg | Bin .../static/img/71tq2sgsacl_sl1500_-307.jpg | Bin .../static/img/71uans-wol_sl1500_-313.jpg | Bin .../static/img/71xi8za0npl_sl1500_-301.jpg | Bin ...ma_dining_chairs_black_walnut_lb01-551.jpg | Bin .../static/img/81c0m6olhjl_sl1500_-131.jpg | Bin .../static/img/81gbmzexsrl_sl1500_-116.jpg | Bin .../static/img/81ggpnkpool_sl1500_-104.jpg | Bin .../static/img/81hd-h2mghl_sl1500_-119.jpg | Bin .../static/img/81ra3tx1yfl_sl1500_-125.jpg | Bin .../static/img/81rt1sqjedl_sl1500_-128.jpg | Bin .../static/img/81ufdwjleal_sl1500_-107.jpg | Bin .../static/img/81wca6qkcul_sl1500_-110.jpg | Bin .../static/img/81zBNebzzNL._SL1500_-122.jpg | Bin .../static/img/91sxta7ujhl_sl1500_-113.jpg | Bin ...uk_thelma_dining_chairs_oak_grey03-518.jpg | Bin ...a_dining_chairs_red_walnut_lb01jpg-554.png | Bin .../static/img/g_631993_a-56.jpg | Bin .../static/img/g_631993_c-59.jpg | Bin .../static/img/g_631993_e-65.jpg | Bin .../static/img/g_631993_g-62.jpg | Bin .../static/img/img_20170505_151457-521.jpg | Bin ...le-office-conference-pedestal-desk-215.jpg | Bin .../static/img/lux_caritatis_blanc-438.jpg | Bin .../static/img/lux_caritatis_rouge-452.jpg | Bin .../static/img/lux_montis1-444.jpg | Bin .../static/img/lux_montis1-455.jpg | Bin .../img/mascara-aloe-vera_748_497-272.jpg | Bin .../img/mascara-aloe-vera_748_497-283.png | Bin .../img/mascara-aloe-vera_806_535-23.jpg | Bin ...e-tv-warm-shaker-bois-massif-183cm-218.jpg | Bin ...warm-shaker-bois-massif-183cm-gris-224.jpg | Bin ...arm-shaker-bois-massif-183cm-scene-221.jpg | Bin ...haker-bois-massif-183cm-scene-gris-227.jpg | Bin ...ern-wood-dining-table-natural-side-155.jpg | Bin ...ffee-table-furniture-craftsman-oak-158.jpg | Bin ...able-furniture-craftsman-oak-close-161.jpg | Bin ...entertainment-credenza-chene-clair-164.jpg | Bin ...ainment-credenza-chene-clair-scene-167.jpg | Bin ...t-credenza-chene-clair-scene-front-170.jpg | Bin .../table-mid-century-natural-wood-152.jpg | Bin .../static/img/table-side-wood-oak-260.jpg | Bin .../static/img/thelma-couple-chair-508.jpg | Bin .../tests/__init__.py | 1 + .../tests/common.py | 187 +++ .../test_shopinvader_search_engine_image.py | 103 ++ .../views/se_backend.xml | 14 + 109 files changed, 1620 insertions(+), 2294 deletions(-) create mode 120000 setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_image create mode 120000 setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_product_image create mode 100644 setup/shopinvader_search_engine_image/setup.py delete mode 100644 shopinvader_image/__init__.py delete mode 100644 shopinvader_image/__manifest__.py delete mode 100644 shopinvader_image/data/ir_export_category.xml delete mode 100644 shopinvader_image/data/ir_export_product.xml delete mode 100644 shopinvader_image/demo/backend_demo.xml delete mode 100644 shopinvader_image/demo/product_image_relation_demo.xml delete mode 100644 shopinvader_image/demo/storage_file_demo.xml delete mode 100644 shopinvader_image/demo/storage_image_demo.xml delete mode 100644 shopinvader_image/hooks.py delete mode 100644 shopinvader_image/i18n/shopinvader_image.pot delete mode 100644 shopinvader_image/models/__init__.py delete mode 100644 shopinvader_image/models/shopinvader_backend.py delete mode 100644 shopinvader_image/models/shopinvader_category.py delete mode 100644 shopinvader_image/models/shopinvader_image_mixin.py delete mode 100644 shopinvader_image/models/shopinvader_image_resize.py delete mode 100644 shopinvader_image/models/shopinvader_variant.py delete mode 100644 shopinvader_image/readme/DESCRIPTION.rst delete mode 100644 shopinvader_image/readme/INSTALL.rst delete mode 100644 shopinvader_image/readme/USAGE.rst delete mode 100644 shopinvader_image/security/ir.model.access.csv delete mode 100644 shopinvader_image/tests/__init__.py delete mode 100644 shopinvader_image/tests/common.py delete mode 100644 shopinvader_image/tests/test_cart.py delete mode 100644 shopinvader_image/tests/test_images.py delete mode 100644 shopinvader_image/views/shopinvader_backend_view.xml delete mode 100644 shopinvader_image/views/shopinvader_image_resize_view.xml rename {shopinvader_image => shopinvader_search_engine_image}/README.rst (100%) create mode 100644 shopinvader_search_engine_image/__init__.py create mode 100644 shopinvader_search_engine_image/__manifest__.py create mode 100644 shopinvader_search_engine_image/demo/fs_product_image.xml rename shopinvader_image/demo/storage_image_product_image_tag_demo.xml => shopinvader_search_engine_image/demo/image_tag.xml (100%) rename shopinvader_image/data/shopinvader_image_resize.xml => shopinvader_search_engine_image/demo/se_thumbnail_size.xml (77%) create mode 100644 shopinvader_search_engine_image/models/__init__.py create mode 100644 shopinvader_search_engine_image/models/se_backend.py rename {shopinvader_image => shopinvader_search_engine_image}/readme/CONTRIBUTORS.rst (100%) create mode 100644 shopinvader_search_engine_image/readme/DESCRIPTION.rst rename {shopinvader_image => shopinvader_search_engine_image}/readme/HISTORY.rst (100%) create mode 100644 shopinvader_search_engine_image/readme/USAGE.rst create mode 100644 shopinvader_search_engine_image/readme/newsfragments/.gitignore create mode 100644 shopinvader_search_engine_image/schemas/__init__.py create mode 100644 shopinvader_search_engine_image/schemas/image_data.py create mode 100644 shopinvader_search_engine_image/schemas/images_mixin.py create mode 100644 shopinvader_search_engine_image/schemas/product_category.py create mode 100644 shopinvader_search_engine_image/schemas/product_product.py rename {shopinvader_image => shopinvader_search_engine_image}/static/description/index.html (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07-524.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/51gnjksrxml_sl1024_-497.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02-515.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/61kcwirwmjl_sl1500_-289.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/61ncsqkegrl_sl1500_-298.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/61vffbcilbl_sl1500_-292.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/61vvazh7fbl_sl1500_-295.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71c62lnhnxl_sx522_-2.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71ezvti-0l_sx522_-32.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71fudutmpl_sl1500_-310.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71guazzso7l_sl1500_-50.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71gulsoprfl_sl1500_-53.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71qy77hpsgl_sx522_-35.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71r0tdtl1sl_sl1500_-304.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71tq2sgsacl_sl1500_-307.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71uans-wol_sl1500_-313.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/71xi8za0npl_sl1500_-301.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01-551.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81c0m6olhjl_sl1500_-131.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81gbmzexsrl_sl1500_-116.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81ggpnkpool_sl1500_-104.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81hd-h2mghl_sl1500_-119.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81ra3tx1yfl_sl1500_-125.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81rt1sqjedl_sl1500_-128.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81ufdwjleal_sl1500_-107.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81wca6qkcul_sl1500_-110.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/81zBNebzzNL._SL1500_-122.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/91sxta7ujhl_sl1500_-113.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03-518.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg-554.png (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/g_631993_a-56.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/g_631993_c-59.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/g_631993_e-65.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/g_631993_g-62.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/img_20170505_151457-521.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk-215.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/lux_caritatis_blanc-438.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/lux_caritatis_rouge-452.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/lux_montis1-444.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/lux_montis1-455.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/mascara-aloe-vera_748_497-272.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/mascara-aloe-vera_748_497-283.png (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/mascara-aloe-vera_806_535-23.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/meuble-tv-warm-shaker-bois-massif-183cm-218.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/meuble-tv-warm-shaker-bois-massif-183cm-gris-224.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-221.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-gris-227.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/mid-century-modern-wood-dining-table-natural-side-155.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-158.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-close-161.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-164.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-167.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-front-170.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/table-mid-century-natural-wood-152.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/table-side-wood-oak-260.jpg (100%) rename {shopinvader_image => shopinvader_search_engine_image}/static/img/thelma-couple-chair-508.jpg (100%) create mode 100644 shopinvader_search_engine_image/tests/__init__.py create mode 100644 shopinvader_search_engine_image/tests/common.py create mode 100644 shopinvader_search_engine_image/tests/test_shopinvader_search_engine_image.py create mode 100644 shopinvader_search_engine_image/views/se_backend.xml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48a65ffb14..1059e0cac7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,6 @@ exclude: | ^shopinvader_easy_binding/| ^shopinvader_elasticsearch/| ^shopinvader_guest_mode/| - ^shopinvader_image/| ^shopinvader_import_image/| ^shopinvader_invoice/| ^shopinvader_lead/| diff --git a/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_image b/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_image new file mode 120000 index 0000000000..9e740e0558 --- /dev/null +++ b/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_image @@ -0,0 +1 @@ +../../../../shopinvader_search_engine_image \ No newline at end of file diff --git a/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_product_image b/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_product_image new file mode 120000 index 0000000000..edf8c5fffc --- /dev/null +++ b/setup/shopinvader_search_engine_image/odoo/addons/shopinvader_search_engine_product_image @@ -0,0 +1 @@ +../../../../shopinvader_search_engine_product_image \ No newline at end of file diff --git a/setup/shopinvader_search_engine_image/setup.py b/setup/shopinvader_search_engine_image/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/shopinvader_search_engine_image/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/shopinvader_image/__init__.py b/shopinvader_image/__init__.py deleted file mode 100644 index cc6b6354ad..0000000000 --- a/shopinvader_image/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import models -from .hooks import post_init_hook diff --git a/shopinvader_image/__manifest__.py b/shopinvader_image/__manifest__.py deleted file mode 100644 index a9a3121b79..0000000000 --- a/shopinvader_image/__manifest__.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2018 Akretion (http://www.akretion.com) -# Copyright 2018 ACSONE SA/NV () -# Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -{ - "name": "Shopinvader image", - "summary": "Add the export of Image for Shopinvader", - "version": "14.0.1.3.0", - "category": "e-commerce", - "website": "https://github.com/shopinvader/odoo-shopinvader", - "author": "Akretion", - "license": "AGPL-3", - "depends": ["shopinvader", "storage_image_product"], - "data": [ - "security/ir.model.access.csv", - "views/shopinvader_backend_view.xml", - "views/shopinvader_image_resize_view.xml", - "data/ir_export_product.xml", - "data/ir_export_category.xml", - "data/shopinvader_image_resize.xml", - ], - "demo": [ - "demo/storage_image_product_image_tag_demo.xml", - "demo/backend_demo.xml", - ], - "installable": False, - "post_init_hook": "post_init_hook", -} diff --git a/shopinvader_image/data/ir_export_category.xml b/shopinvader_image/data/ir_export_category.xml deleted file mode 100644 index 9e859144f4..0000000000 --- a/shopinvader_image/data/ir_export_category.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - images - - - - diff --git a/shopinvader_image/data/ir_export_product.xml b/shopinvader_image/data/ir_export_product.xml deleted file mode 100644 index b5f759dbcd..0000000000 --- a/shopinvader_image/data/ir_export_product.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - images - - - - diff --git a/shopinvader_image/demo/backend_demo.xml b/shopinvader_image/demo/backend_demo.xml deleted file mode 100644 index 30ffaa26cd..0000000000 --- a/shopinvader_image/demo/backend_demo.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/shopinvader_image/demo/product_image_relation_demo.xml b/shopinvader_image/demo/product_image_relation_demo.xml deleted file mode 100644 index 5e7f6a7554..0000000000 --- a/shopinvader_image/demo/product_image_relation_demo.xml +++ /dev/null @@ -1,593 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/shopinvader_image/demo/storage_file_demo.xml b/shopinvader_image/demo/storage_file_demo.xml deleted file mode 100644 index 3080f10326..0000000000 --- a/shopinvader_image/demo/storage_file_demo.xml +++ /dev/null @@ -1,567 +0,0 @@ - - - - - 71fudutmpl_sl1500_.jpg - - image - - - - - g_631993_a.jpg - - image - - - - - 71tq2sgsacl_sl1500_.jpg - - image - - - - - meuble-tv-warm-shaker-bois-massif-183cm-scene.jpg - - image - - - - - 71c62lnhnxl_sx522_.jpg - - image - - - - - 81gbmzexsrl_sl1500_.jpg - - image - - - - - 61ncsqkegrl_sl1500_.jpg - - image - - - - - c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg.png - - image - - - - - 51gnjksrxml_sl1024_.jpg - - image - - - - - thelma-couple-chair.jpg - - image - - - - - table-mid-century-natural-wood.jpg - - image - - - - - 71qy77hpsgl_sx522_.jpg - - image - - - - - mid-century-modern-wood-dining-table-natural-side.jpg - - image - - - - - 61vffbcilbl_sl1500_.jpg - - image - - - - - 81hd-h2mghl_sl1500_.jpg - - image - - - - - meuble-tv-warm-shaker-bois-massif-183cm-gris.jpg - - image - - - - - sauder-harvey-park-entertainment-credenza-chene-clair-scene.jpg - - image - - - - - 71xi8za0npl_sl1500_.jpg - - image - - - - - 71r0tdtl1sl_sl1500_.jpg - - image - - - - - 2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07.jpg - - image - - - - - 81c0m6olhjl_sl1500_.jpg - - image - - - - - 73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01.jpg - - image - - - - - 81ufdwjleal_sl1500_.jpg - - image - - - - - g_631993_c.jpg - - image - - - - - 81wca6qkcul_sl1500_.jpg - - image - - - - - 71guazzso7l_sl1500_.jpg - - image - - - - - 81rt1sqjedl_sl1500_.jpg - - image - - - - - 91sxta7ujhl_sl1500_.jpg - - image - - - - - sauder-420011-coffee-table-furniture-craftsman-oak.jpg - - image - - - - - 61vvazh7fbl_sl1500_.jpg - - image - - - - - sauder-harvey-park-entertainment-credenza-chene-clair.jpg - - image - - - - - g_631993_e.jpg - - image - - - - - kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk.jpg - - image - - - - - 61kcwirwmjl_sl1500_.jpg - - image - - - - - meuble-tv-warm-shaker-bois-massif-183cm-scene-gris.jpg - - image - - - - - 81ggpnkpool_sl1500_.jpg - - image - - - - - 71gulsoprfl_sl1500_.jpg - - image - - - - - 71uans-wol_sl1500_.jpg - - image - - - - - 5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02.jpg - - image - - - - - 9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03.jpg - - image - - - - - img_20170505_151457.jpg - - image - - - - - 81zBNebzzNL._SL1500_.jpg - - image - - - - - sauder-420011-coffee-table-furniture-craftsman-oak-close.jpg - - image - - - - - table-side-wood-oak.jpg - - image - - - - - meuble-tv-warm-shaker-bois-massif-183cm.jpg - - image - - - - - 71ezvti-0l_sx522_.jpg - - image - - - - - g_631993_g.jpg - - image - - - - - sauder-harvey-park-entertainment-credenza-chene-clair-scene-front.jpg - - image - - - - - 81ra3tx1yfl_sl1500_.jpg - - image - - - - diff --git a/shopinvader_image/demo/storage_image_demo.xml b/shopinvader_image/demo/storage_image_demo.xml deleted file mode 100644 index f35852028e..0000000000 --- a/shopinvader_image/demo/storage_image_demo.xml +++ /dev/null @@ -1,322 +0,0 @@ - - - - - 71c62lnhnxl_sx522_.jpg - - - - - - 71ezvti-0l_sx522_.jpg - - - - - - 71qy77hpsgl_sx522_.jpg - - - - - - 71guazzso7l_sl1500_.jpg - - - - - - 71gulsoprfl_sl1500_.jpg - - - - - - g_631993_a.jpg - - - - - - g_631993_c.jpg - - - - - - g_631993_g.jpg - - - - - - g_631993_e.jpg - - - - - - 81ggpnkpool_sl1500_.jpg - - - - - - 81ufdwjleal_sl1500_.jpg - - - - - - 81wca6qkcul_sl1500_.jpg - - - - - - 91sxta7ujhl_sl1500_.jpg - - - - - - 81gbmzexsrl_sl1500_.jpg - - - - - - 81hd-h2mghl_sl1500_.jpg - - - - - - 81zBNebzzNL._SL1500_.jpg - - - - - - 81ra3tx1yfl_sl1500_.jpg - - - - - - 81rt1sqjedl_sl1500_.jpg - - - - - - 81c0m6olhjl_sl1500_.jpg - - - - - - table-mid-century-natural-wood.jpg - - - - - - mid-century-modern-wood-dining-table-natural-side.jpg - - - - - - sauder-420011-coffee-table-furniture-craftsman-oak.jpg - - - - - - sauder-420011-coffee-table-furniture-craftsman-oak-close.jpg - - - - - - sauder-harvey-park-entertainment-credenza-chene-clair.jpg - - - - - - sauder-harvey-park-entertainment-credenza-chene-clair-scene.jpg - - - - - - sauder-harvey-park-entertainment-credenza-chene-clair-scene-front.jpg - - - - - - kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk.jpg - - - - - - meuble-tv-warm-shaker-bois-massif-183cm.jpg - - - - - - meuble-tv-warm-shaker-bois-massif-183cm-scene.jpg - - - - - - meuble-tv-warm-shaker-bois-massif-183cm-gris.jpg - - - - - - meuble-tv-warm-shaker-bois-massif-183cm-scene-gris.jpg - - - - - - table-side-wood-oak.jpg - - - - - - 61kcwirwmjl_sl1500_.jpg - - - - - - 61vffbcilbl_sl1500_.jpg - - - - - - 61vvazh7fbl_sl1500_.jpg - - - - - - 61ncsqkegrl_sl1500_.jpg - - - - - - 71xi8za0npl_sl1500_.jpg - - - - - - 71r0tdtl1sl_sl1500_.jpg - - - - - - 71tq2sgsacl_sl1500_.jpg - - - - - - 71fudutmpl_sl1500_.jpg - - - - - - 71uans-wol_sl1500_.jpg - - - - - - 51gnjksrxml_sl1024_.jpg - - - - - - thelma-couple-chair.jpg - - - - - - 5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02.jpg - - - - - - 9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03.jpg - - - - - - img_20170505_151457.jpg - - - - - - 2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07.jpg - - - - - - 73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01.jpg - - - - - - c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg.png - - - - - diff --git a/shopinvader_image/hooks.py b/shopinvader_image/hooks.py deleted file mode 100644 index ad2b340e6c..0000000000 --- a/shopinvader_image/hooks.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2019 ACSONE SA/NV (http://acsone.eu) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import SUPERUSER_ID, tools -from odoo.api import Environment -from odoo.modules.module import get_resource_path - -DEMO_POST_INIT = [ - "demo/storage_file_demo.xml", - "demo/storage_image_demo.xml", - "demo/product_image_relation_demo.xml", -] - - -def load_xml(env, module, filepath): - tools.convert_file( - env.cr, - module, - get_resource_path(module, filepath), - {}, - mode="init", - noupdate=False, - ) - - -def post_init_hook(cr, registry): - env = Environment(cr, SUPERUSER_ID, {}) - module_obj = env["ir.module.module"] - module = module_obj.search([("name", "=", "shopinvader_image")]) - if module.demo: - # Loaded data requires that the component registry is loaded! - # The components registry is loaded at the end of the server - # initialization. By default demo data are loaded as part of the - # server initialization process. Unfortunately, since the way images - # are stored is managed by components we need that these components - # are available when creating an image. We must therefore delay the - # creation of our demo images to take place once the server is fully - # initialized and components are ready to be used. That's why these - # demo data files are loaded into a post_init_hook in place of - # the normal process. - builder = env["component.builder"] - # build the components of every installed addons - comp_registry = builder._init_global_registry() - builder.build_registry(comp_registry, states=("installed",)) - # build the components of the current tested addon - env["component.builder"].load_components("shopinvader_image") - # load data requiring components - for demo in DEMO_POST_INIT: - load_xml(env, "shopinvader_image", demo) - # prevent removal of demo data since the xml files are not declared - # into the demo section and therefore the xml_ids are no more found on - # addon update - cr.execute( - """ - update - ir_model_data - set - module='__export__' - where - module='shopinvader_image' - and model in ( - 'storage.file', - 'storage.image', - 'product.image.relation', - 'product.product' - ) - """ - ) diff --git a/shopinvader_image/i18n/shopinvader_image.pot b/shopinvader_image/i18n/shopinvader_image.pot deleted file mode 100644 index cf7d968378..0000000000 --- a/shopinvader_image/i18n/shopinvader_image.pot +++ /dev/null @@ -1,186 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * shopinvader_image -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 14.0\n" -"Report-Msgid-Bugs-To: \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: shopinvader_image -#: model:ir.model.fields,help:shopinvader_image.field_shopinvader_backend__image_data_include_cdn_url -msgid "" -"\n" -"Enable this flag to control\n" -"whether the CDN URL must be included or not\n" -"in the URL stored in images' JSON data.\n" -"\n" -"OFF: the URL will NOT include the CDN URL (eg: only the relative path);\n" -"ON: the URL will include the CDN URL;\n" -"\n" -"Excluding the URL can be useful to:\n" -"\n" -"1. reduce payload size w/o duplicating data\n" -"2. allow using the same storage w/ different CDN\n" -"\n" -"If you use this option,\n" -"take care of adding the CDN URL on your frontend\n" -"to all images' relative path.\n" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend__shopinvader_category_resize_ids -msgid "Category Image Size" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__create_uid -msgid "Created by" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__create_date -msgid "Created on" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend__display_name -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category__display_name -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin__display_name -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__display_name -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant__display_name -msgid "Display Name" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend__id -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category__id -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin__id -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__id -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant__id -msgid "ID" -msgstr "" - -#. module: shopinvader_image -#: model:ir.ui.menu,name:shopinvader_image.shopinvader_image_resize_menu -msgid "Image Resize" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend__image_data_include_cdn_url -msgid "Image URLs w/ CDN" -msgstr "" - -#. module: shopinvader_image -#: model:ir.ui.menu,name:shopinvader_image.menu_shopinvader_config_image -#: model_terms:ir.ui.view,arch_db:shopinvader_image.shopinvader_backend_view_form -msgid "Images" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category__images_store_hash -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin__images_store_hash -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant__images_store_hash -msgid "Images Store Hash" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category__images_stored -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin__images_stored -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant__images_stored -msgid "Images Stored" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__key -msgid "Key" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend____last_update -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category____last_update -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin____last_update -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize____last_update -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant____last_update -msgid "Last Modified on" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__write_uid -msgid "Last Updated by" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__write_date -msgid "Last Updated on" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model,name:shopinvader_image.model_shopinvader_backend -msgid "Locomotive CMS Backend" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__name -#: model_terms:ir.ui.view,arch_db:shopinvader_image.shopinvader_image_resize_search_view -msgid "Name" -msgstr "" - -#. module: shopinvader_image -#: model_terms:ir.ui.view,arch_db:shopinvader_image.shopinvader_image_resize_tree_view -msgid "Product" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_backend__shopinvader_variant_resize_ids -msgid "Product Image Size" -msgstr "" - -#. module: shopinvader_image -#: model_terms:ir.ui.view,arch_db:shopinvader_image.shopinvader_image_resize_search_view -msgid "Products" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model,name:shopinvader_image.model_shopinvader_category -msgid "Shopinvader Category" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_category__images -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_mixin__images -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_variant__images -msgid "Shopinvader Image" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model,name:shopinvader_image.model_shopinvader_image_mixin -msgid "Shopinvader Image Mixin" -msgstr "" - -#. module: shopinvader_image -#: model:ir.actions.act_window,name:shopinvader_image.shopinvader_image_resize_act_window -#: model:ir.model,name:shopinvader_image.model_shopinvader_image_resize -msgid "Shopinvader Image Resize" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model,name:shopinvader_image.model_shopinvader_variant -msgid "Shopinvader Variant" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__size_x -msgid "Size X" -msgstr "" - -#. module: shopinvader_image -#: model:ir.model.fields,field_description:shopinvader_image.field_shopinvader_image_resize__size_y -msgid "Size Y" -msgstr "" diff --git a/shopinvader_image/models/__init__.py b/shopinvader_image/models/__init__.py deleted file mode 100644 index 091f47c905..0000000000 --- a/shopinvader_image/models/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from . import shopinvader_backend -from . import shopinvader_image_mixin -from . import shopinvader_image_resize -from . import shopinvader_category -from . import shopinvader_variant diff --git a/shopinvader_image/models/shopinvader_backend.py b/shopinvader_image/models/shopinvader_backend.py deleted file mode 100644 index 803400c85c..0000000000 --- a/shopinvader_image/models/shopinvader_backend.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# Copyright 2022 Camptocamp SA (http://www.camptocamp.com) -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import fields, models - -CDN_HELP_TEXT = """ -Enable this flag to control -whether the CDN URL must be included or not -in the URL stored in images' JSON data. - -OFF: the URL will NOT include the CDN URL (eg: only the relative path); -ON: the URL will include the CDN URL; - -Excluding the URL can be useful to: - -1. reduce payload size w/o duplicating data -2. allow using the same storage w/ different CDN - -If you use this option, -take care of adding the CDN URL on your frontend -to all images' relative path. -""" - - -class ShopinvaderBackend(models.Model): - _inherit = "shopinvader.backend" - - shopinvader_variant_resize_ids = fields.Many2many( - comodel_name="shopinvader.image.resize", - relation="product_image_resize", - string="Product Image Size", - ) - shopinvader_category_resize_ids = fields.Many2many( - comodel_name="shopinvader.image.resize", - relation="category_image_resize", - string="Category Image Size", - ) - # TODO: set default False in v > 15. - image_data_include_cdn_url = fields.Boolean( - string="Image URLs w/ CDN", - help=CDN_HELP_TEXT, - default=True, - ) diff --git a/shopinvader_image/models/shopinvader_category.py b/shopinvader_image/models/shopinvader_category.py deleted file mode 100644 index 6364a25a64..0000000000 --- a/shopinvader_image/models/shopinvader_category.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -from odoo import models - - -class ShopinvaderCategory(models.Model): - _name = "shopinvader.category" - _inherit = ["shopinvader.category", "shopinvader.image.mixin"] - _image_field = "image_ids" diff --git a/shopinvader_image/models/shopinvader_image_mixin.py b/shopinvader_image/models/shopinvader_image_mixin.py deleted file mode 100644 index 5b3d6d6981..0000000000 --- a/shopinvader_image/models/shopinvader_image_mixin.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# Copyright 2021 Camptocamp SA (http://www.camptocamp.com) -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import fields, models - -from odoo.addons.base_sparse_field.models.fields import Serialized - - -class ShopinvaderImageMixin(models.AbstractModel): - _name = "shopinvader.image.mixin" - _description = "Shopinvader Image Mixin" - _image_field = None - - images = Serialized( - compute="_compute_images", - string="Shopinvader Image", - compute_sudo=True, - ) - # Tech field to store images data. - # It cannot be computed because the computation - # might required generating thumbs - # which requires access to the storage files - # which requires components registry to be available - # which is not the case when Odoo starts. - images_stored = Serialized() - images_store_hash = fields.Char() - - def _compute_images(self): - # Force computation if needed - self.filtered(lambda x: x._images_must_recompute())._compute_images_stored() - for record in self: - record.images = record.images_stored - - def _compute_images_stored(self): - for record in self: - record.images_stored = record._get_image_data_for_record() - record.images_store_hash = record._get_images_store_hash() - - def _images_must_recompute(self): - return self.images_store_hash != self._get_images_store_hash() - - @property - def _resize_scales_field(self): - return "%s_resize_ids" % self._name.replace(".", "_") - - def _resize_scales(self): - return self.backend_id[self._resize_scales_field] - - def _get_images_store_hash(self): - self.ensure_one() - if not self[self._image_field]: - return False - return str(hash(self._get_images_store_hash_tuple())) - - def _get_images_store_hash_timestamp(self): - """Get the timestamp of the last modification of the images - - This also includes the last modification of their relation or tags records - - :return: datetime - """ - images_relation = self[self._image_field] - timestamps = [ - *images_relation.mapped("write_date"), - *images_relation.mapped("image_id.write_date"), - ] - if "tag_id" in images_relation._fields: - timestamps += images_relation.mapped("tag_id.write_date") - return max(timestamps) if timestamps else False - - def _get_images_store_hash_tuple(self): - images = self[self._image_field].image_id - # Get fresh URLs. - # Normally we have only one backend - # but potentially you can have different backends by image record. - # If any base URL changes, images should be recomputed. - # Eg: swap an image to another backend or change the CDN URL. - # NOTE: this is not perfect in terms of perf because it will cause - # calls to `get_or_create_thumbnail` when no image data has changed - # but it's better than having broken URLs. - public_urls = tuple([self._get_image_url(x) for x in images]) - resize_scales = tuple( - self._resize_scales().mapped(lambda r: (r.key, r.size_x, r.size_y)) - ) - timestamp = self._get_images_store_hash_timestamp() - # TODO: any other bit to consider here? - return resize_scales + public_urls + (timestamp,) - - def _get_image_url_key(self, image_relation): - # You can inherit this method to change the name of the image of - # your website. By default we use the name of the product or category - # linked to the image processed - # Note the url will be slugify by the get_or_create_thumnail - self.ensure_one() - return self.display_name - - def _get_image_data_for_record(self): - self.ensure_one() - res = [] - resizes = self._resize_scales() - for image_relation in self[self._image_field]: - url_key = self._get_image_url_key(image_relation) - image_data = {} - for resize in resizes: - thumbnail = image_relation.image_id.get_or_create_thumbnail( - resize.size_x, resize.size_y, url_key=url_key - ) - image_data[resize.key] = self._prepare_data_resize( - thumbnail, image_relation - ) - res.append(image_data) - return res - - def _prepare_data_resize(self, thumbnail, image_relation): - """Prepare data to fill images serialized field - - :param thumbnail: ``storage.thumbnail`` recordset - :param image_relation: ``image.relation.abstract`` recordset - :return: dict - """ - self.ensure_one() - res = {"src": self._get_image_url(thumbnail), "alt": self.name} - if "tag_id" in image_relation._fields: - res["tag"] = image_relation.tag_id.name or "" - return res - - def _get_image_url(self, image): - fname = "url" if self.backend_id.image_data_include_cdn_url else "url_path" - return image[fname] diff --git a/shopinvader_image/models/shopinvader_image_resize.py b/shopinvader_image/models/shopinvader_image_resize.py deleted file mode 100644 index d872254773..0000000000 --- a/shopinvader_image/models/shopinvader_image_resize.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import api, fields, models - - -class ShopinvaderImageResize(models.Model): - _name = "shopinvader.image.resize" - _description = "Shopinvader Image Resize" - - name = fields.Char(required=True) - key = fields.Char(required=True) - size_x = fields.Integer(required=True) - size_y = fields.Integer(required=True) - - @api.depends("size_x", "size_y") - def _compute_display_name(self): - for record in self: - record.display_name = "{} ({}x{})".format( - record.name, record.size_x, record.size_y - ) diff --git a/shopinvader_image/models/shopinvader_variant.py b/shopinvader_image/models/shopinvader_variant.py deleted file mode 100644 index 5f8e0f9c62..0000000000 --- a/shopinvader_image/models/shopinvader_variant.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models - - -class ShopinvaderVariant(models.Model): - _name = "shopinvader.variant" - _inherit = ["shopinvader.variant", "shopinvader.image.mixin"] - _image_field = "variant_image_ids" diff --git a/shopinvader_image/readme/DESCRIPTION.rst b/shopinvader_image/readme/DESCRIPTION.rst deleted file mode 100644 index a87b06a0a1..0000000000 --- a/shopinvader_image/readme/DESCRIPTION.rst +++ /dev/null @@ -1,2 +0,0 @@ -This module builds up on functionality defined in storage_image to define new Shopinvader-specific functionality, -and implements them on the Shopinvader version of categories and variants. diff --git a/shopinvader_image/readme/INSTALL.rst b/shopinvader_image/readme/INSTALL.rst deleted file mode 100644 index 4a03a97578..0000000000 --- a/shopinvader_image/readme/INSTALL.rst +++ /dev/null @@ -1 +0,0 @@ -Follow the documentation of the storage_backend module diff --git a/shopinvader_image/readme/USAGE.rst b/shopinvader_image/readme/USAGE.rst deleted file mode 100644 index 8b6db0af78..0000000000 --- a/shopinvader_image/readme/USAGE.rst +++ /dev/null @@ -1,4 +0,0 @@ -Essentially, call _compute_images whenever you want to refresh all image thumbnails/resizes -on your records. Resized images are then accessible through the "images" serialized field. - -For an example of full implementation on a new model, you can view shopinvader_banner. diff --git a/shopinvader_image/security/ir.model.access.csv b/shopinvader_image/security/ir.model.access.csv deleted file mode 100644 index 250e6a9a3b..0000000000 --- a/shopinvader_image/security/ir.model.access.csv +++ /dev/null @@ -1,3 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_shopinvader_image_resize_edit,access_shopinvader_image_resize_edit,model_shopinvader_image_resize,shopinvader.group_shopinvader_manager,1,1,1,1 -access_shopinvader_image_resize_read,access_shopinvader_image_resize_read,model_shopinvader_image_resize,base.group_user,1,0,0,0 diff --git a/shopinvader_image/tests/__init__.py b/shopinvader_image/tests/__init__.py deleted file mode 100644 index e55fa6532c..0000000000 --- a/shopinvader_image/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import test_images -from . import test_cart diff --git a/shopinvader_image/tests/common.py b/shopinvader_image/tests/common.py deleted file mode 100644 index 3cba153dc6..0000000000 --- a/shopinvader_image/tests/common.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# Copyright 2020 Camptocamp (http://www.camptocamp.com) -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -from odoo.addons.shopinvader.tests.common import ProductCommonCase -from odoo.addons.storage_image_product.tests.common import ProductImageCommonCase - - -class TestShopinvaderImageCase(ProductCommonCase, ProductImageCommonCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - ProductImageCommonCase.setUpClass() - cls.logo = cls.env["product.image.relation"].create( - {"product_tmpl_id": cls.template.id, "image_id": cls.logo_image.id} - ) - cls.image_bk = cls.env["product.image.relation"].create( - { - "product_tmpl_id": cls.template.id, - "image_id": cls.black_image.id, - "attribute_value_ids": [ - ( - 6, - 0, - [cls.env.ref("product.product_attribute_value_4").id], - ) - ], - } - ) diff --git a/shopinvader_image/tests/test_cart.py b/shopinvader_image/tests/test_cart.py deleted file mode 100644 index 580d535d8d..0000000000 --- a/shopinvader_image/tests/test_cart.py +++ /dev/null @@ -1,11 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo.addons.shopinvader.tests.test_cart import CommonConnectedCartCase - - -class ShopinvaderCartCase(CommonConnectedCartCase): - def test_get_cart_image_info(self): - response = self.service.dispatch("search") - self.assertIn("images", response["data"]["lines"]["items"][0]["product"]) diff --git a/shopinvader_image/tests/test_images.py b/shopinvader_image/tests/test_images.py deleted file mode 100644 index 3febdba8e8..0000000000 --- a/shopinvader_image/tests/test_images.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2017 Akretion (http://www.akretion.com). -# @author Sébastien BEAU -# Copyright 2021 Camptocamp SA (http://www.camptocamp.com) -# @author Simone Orsi -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from datetime import timedelta - -import mock - -from odoo import fields - -from .common import TestShopinvaderImageCase - - -class TestShopinvaderImage(TestShopinvaderImageCase): - # TODO: test permission explicitely if needed - - def test_basic_images_compute(self): - storage_backend = self.shopinvader_variant.image_ids.image_id.backend_id - storage_backend.write( - { - "served_by": "external", - "base_url": "https://foo.com", - } - ) - images = self.shopinvader_variant.images - self.assertEqual(len(images), 2) - for image in images: - for scale in self.backend.shopinvader_variant_resize_ids: - img = image[scale.key] - self.assertEqual(img["alt"], self.shopinvader_variant.name) - self.assertTrue( - img["src"].startswith( - "https://foo.com/customizable-desk-config_{0.size_x}_{0.size_y}".format( - scale - ) - ) - ) - self.assertIn("tag", img) - - def test_basic_images_compute_no_cdn_url(self): - storage_backend = self.shopinvader_variant.image_ids.image_id.backend_id - storage_backend.write( - { - "served_by": "external", - "base_url": "https://foo.com", - } - ) - self.backend.image_data_include_cdn_url = False - images = self.shopinvader_variant.images - self.assertEqual(len(images), 2) - for image in images: - for scale in self.backend.shopinvader_variant_resize_ids: - img = image[scale.key] - self.assertEqual(img["alt"], self.shopinvader_variant.name) - self.assertTrue( - img["src"].startswith( - "/customizable-desk-config_{0.size_x}_{0.size_y}".format(scale) - ) - ) - self.assertIn("tag", img) - - def test_hash_and_compute_flag(self): - variant = self.shopinvader_variant - self.assertFalse(variant.images_store_hash) - self.assertTrue(variant._images_must_recompute()) - variant.images_store_hash = variant._get_images_store_hash() - self.assertFalse(variant._images_must_recompute()) - # change hash by changing scale - self.backend.shopinvader_variant_resize_ids[0].key = "very-small" - self.assertTrue(variant._images_must_recompute()) - variant.images_store_hash = variant._get_images_store_hash() - # NOTE: write_date, used to compute the hash, uses sql NOW() to recompute - # and it always corresponds to the time the transaction started. - # To overcome this, we manually overwrite write_date - now = fields.Datetime.now() - variant.image_ids.write_date = now - variant.images_store_hash = variant._get_images_store_hash() - # Change hash when relation is updated - variant.image_ids[0].write_date = now + timedelta(seconds=1) - self.assertTrue(variant._images_must_recompute()) - variant.images_store_hash = variant._get_images_store_hash() - # Change hash when image is updated - variant.image_ids[0].image_id.write_date = now + timedelta(seconds=2) - self.assertTrue(variant._images_must_recompute()) - variant.images_store_hash = variant._get_images_store_hash() - # Change hash when tag is updated - tag = self.env.ref("shopinvader_image.image_tag_1") - variant.image_ids[0].tag_id = tag - variant.images_store_hash = variant._get_images_store_hash() - tag.write_date = now + timedelta(seconds=3) - self.assertTrue(variant._images_must_recompute()) - variant.images_store_hash = variant._get_images_store_hash() - - def test_images_recompute(self): - variant = self.shopinvader_variant - self.assertTrue(variant._images_must_recompute()) - with mock.patch.object(type(variant), "_get_image_data_for_record") as mocked: - mocked.return_value = [{"a": 1, "b": 2}] - self.assertEqual(variant.images, [{"a": 1, "b": 2}]) - mocked.assert_called() - - variant.invalidate_cache(["images"]) - self.assertFalse(variant._images_must_recompute()) - with mock.patch.object(type(variant), "_get_image_data_for_record") as mocked: - mocked.return_value = [{"c": 3, "d": 4}] - # same value as before - self.assertEqual(variant.images, [{"a": 1, "b": 2}]) - mocked.assert_not_called() - - # simulate change in image scale - self.backend.shopinvader_variant_resize_ids[0].key = "very-small" - variant.invalidate_cache(["images"]) - self.assertTrue(variant._images_must_recompute()) - with mock.patch.object(type(variant), "_get_image_data_for_record") as mocked: - mocked.return_value = [{"c": 3, "d": 4}] - # recomputed - self.assertEqual(variant.images, [{"c": 3, "d": 4}]) - mocked.assert_called() - - # Simulate base URL change - self.assertFalse(variant._images_must_recompute()) - random_image = variant.variant_image_ids[0].image_id - # test backend serves images via odoo base url - self.env["ir.config_parameter"].sudo().set_param( - "web.base.url", "https://foo.com" - ) - random_image.invalidate_cache() - self.assertTrue(variant._images_must_recompute()) diff --git a/shopinvader_image/views/shopinvader_backend_view.xml b/shopinvader_image/views/shopinvader_backend_view.xml deleted file mode 100644 index a587bade67..0000000000 --- a/shopinvader_image/views/shopinvader_backend_view.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - shopinvader.backend - - - - - - - - - - - - - diff --git a/shopinvader_image/views/shopinvader_image_resize_view.xml b/shopinvader_image/views/shopinvader_image_resize_view.xml deleted file mode 100644 index 982bc45707..0000000000 --- a/shopinvader_image/views/shopinvader_image_resize_view.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - shopinvader.image.resize - - - - - - - - - shopinvader.image.resize - - - - - - - - - - - - - Shopinvader Image Resize - shopinvader.image.resize - tree - [] - - {} - - - - - - - - diff --git a/shopinvader_image/README.rst b/shopinvader_search_engine_image/README.rst similarity index 100% rename from shopinvader_image/README.rst rename to shopinvader_search_engine_image/README.rst diff --git a/shopinvader_search_engine_image/__init__.py b/shopinvader_search_engine_image/__init__.py new file mode 100644 index 0000000000..106fc57265 --- /dev/null +++ b/shopinvader_search_engine_image/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import schemas diff --git a/shopinvader_search_engine_image/__manifest__.py b/shopinvader_search_engine_image/__manifest__.py new file mode 100644 index 0000000000..792264dea5 --- /dev/null +++ b/shopinvader_search_engine_image/__manifest__.py @@ -0,0 +1,28 @@ +# Copyright 2018 Akretion (http://www.akretion.com) +# Copyright 2023 ACSONE SA/NV () +# Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Shopinvader image", + "summary": "Add the export of Image for Shopinvader", + "version": "16.0.1.0.0", + "category": "e-commerce", + "website": "https://github.com/shopinvader/odoo-shopinvader", + "author": "Akretion, ACSONE SA/NV", + "license": "AGPL-3", + "depends": [ + "shopinvader_search_engine", + "search_engine_image_thumbnail", + "fs_product_multi_image", + ], + "data": [ + "views/se_backend.xml", + ], + "demo": [ + "demo/image_tag.xml", + "demo/se_thumbnail_size.xml", + "demo/fs_product_image.xml", + ], + "installable": True, + "development_status": "Alpha", +} diff --git a/shopinvader_search_engine_image/demo/fs_product_image.xml b/shopinvader_search_engine_image/demo/fs_product_image.xml new file mode 100644 index 0000000000..f0c8c470c7 --- /dev/null +++ b/shopinvader_search_engine_image/demo/fs_product_image.xml @@ -0,0 +1,1057 @@ + + + + + + + + + + + + + 1 + + + + + + + + + + 1 + + + + + + + 2 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + 5 + + + + + + + + 6 + + + + + + + + 7 + + + + + + + + 8 + + + + + + + + 9 + + + + + + + + 10 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + + + + 1 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + + + 3 + + + + + + + + + + 1 + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + + + 2 + + + + + + + + 3 + + + + + + + + 4 + + + + + + + + 5 + + + + + + + + 6 + + + + + + + + + + 1 + + + + + + + + + 1 + + + + + + + 2 + + + + + + + 3 + + + + + + + 4 + + + + + + + + 5 + + + + + + + + 6 + + + diff --git a/shopinvader_image/demo/storage_image_product_image_tag_demo.xml b/shopinvader_search_engine_image/demo/image_tag.xml similarity index 100% rename from shopinvader_image/demo/storage_image_product_image_tag_demo.xml rename to shopinvader_search_engine_image/demo/image_tag.xml diff --git a/shopinvader_image/data/shopinvader_image_resize.xml b/shopinvader_search_engine_image/demo/se_thumbnail_size.xml similarity index 77% rename from shopinvader_image/data/shopinvader_image_resize.xml rename to shopinvader_search_engine_image/demo/se_thumbnail_size.xml index 88cfb6d74a..d8f02e1ea1 100644 --- a/shopinvader_image/data/shopinvader_image_resize.xml +++ b/shopinvader_search_engine_image/demo/se_thumbnail_size.xml @@ -1,21 +1,21 @@ - + Shop Small small 60 60 - + Shop Medium medium 300 300 - + Shop Large large 500 diff --git a/shopinvader_search_engine_image/models/__init__.py b/shopinvader_search_engine_image/models/__init__.py new file mode 100644 index 0000000000..36858c277d --- /dev/null +++ b/shopinvader_search_engine_image/models/__init__.py @@ -0,0 +1 @@ +from . import se_backend diff --git a/shopinvader_search_engine_image/models/se_backend.py b/shopinvader_search_engine_image/models/se_backend.py new file mode 100644 index 0000000000..0203004a70 --- /dev/null +++ b/shopinvader_search_engine_image/models/se_backend.py @@ -0,0 +1,80 @@ +# Copyright 2017 Akretion (http://www.akretion.com). +# @author Sébastien BEAU +# Copyright 2022 Camptocamp SA (http://www.camptocamp.com) +# @author Simone Orsi +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import UserError + +from odoo.addons.fs_image.fields import FSImageValue + +CDN_HELP_TEXT = """ + +The URL is one of the fields stored in the image's JSON data exported to the +search engine. The images exported are stored in a filesystem storage. +Therefore, the image is addressable in a different. + +* By default, an internal url can be used to access the image through the + Odoo server. +* On a fs.storage backend, you can also specifiy a base url to access the + image directly through the storage server. This is useful to avoid + unnecessary load on the Odoo server. This url is available in the + `url`field of the image's JSON data. + +When indexing the images, you can also choose to only export the relative +path of the image. This is useful if you want to use the same storage +backend with different CDN and will reduce the payload size w/o duplicating +data. + +To resume, you can choose between 3 options: + +* `Odoo URL`: the URL will be the internal URL of the Odoo server +* `FS Storage URL`: the URL will be the URL of the image served by the storage server +* `Relative path URL`: the URL will be the relative path of the image + +In the last case, you must take care of adding the CDN URL on your frontend to +all images' relative path. +""" + + +class SeBackend(models.Model): + _inherit = "se.backend" + + image_data_url_strategy = fields.Selection( + selection=[ + ("odoo", "Odoo URL"), + ("storage_url", "FS Storage URL"), + ("url_path", "Relative path URL"), + ], + help=CDN_HELP_TEXT, + default="odoo", + ) + + def _get_image_url_for_image(self, image: FSImageValue) -> str: + """Get the URL of the image. + + :param image: The image + :return: The URL of the image + """ + self.ensure_one() + if self.image_data_url_strategy == "odoo": + value = image.internal_url + elif self.image_data_url_strategy == "storage_url": + value = image.url + elif self.image_data_url_strategy == "url_path": + value = image.url_path + else: + raise ValueError( + f"Invalid image_data_url_strategy: {self.image_data_url_strategy}" + ) + if not value: + raise UserError( + _( + "No URL found for image %(image_name)s with strategy %(strategy)s", + image_name=image.name, + strategy=self.image_data_url_strategy, + ) + ) + return value diff --git a/shopinvader_image/readme/CONTRIBUTORS.rst b/shopinvader_search_engine_image/readme/CONTRIBUTORS.rst similarity index 100% rename from shopinvader_image/readme/CONTRIBUTORS.rst rename to shopinvader_search_engine_image/readme/CONTRIBUTORS.rst diff --git a/shopinvader_search_engine_image/readme/DESCRIPTION.rst b/shopinvader_search_engine_image/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..61a5450ffc --- /dev/null +++ b/shopinvader_search_engine_image/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +This module extends the search_engine_image_thumbnail module to generate +thumbnails for images for products and categories. The related information +is then exported to the search engine as part of the product and category +data. diff --git a/shopinvader_image/readme/HISTORY.rst b/shopinvader_search_engine_image/readme/HISTORY.rst similarity index 100% rename from shopinvader_image/readme/HISTORY.rst rename to shopinvader_search_engine_image/readme/HISTORY.rst diff --git a/shopinvader_search_engine_image/readme/USAGE.rst b/shopinvader_search_engine_image/readme/USAGE.rst new file mode 100644 index 0000000000..e07839828d --- /dev/null +++ b/shopinvader_search_engine_image/readme/USAGE.rst @@ -0,0 +1,3 @@ +To activate the generation and the export of the thumbnails information +to a search engine, you must define thumbnails size and configure on you index +the sizes you want to export and for which fields theses sizes are valid. diff --git a/shopinvader_search_engine_image/readme/newsfragments/.gitignore b/shopinvader_search_engine_image/readme/newsfragments/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shopinvader_search_engine_image/schemas/__init__.py b/shopinvader_search_engine_image/schemas/__init__.py new file mode 100644 index 0000000000..8c0e8a7b48 --- /dev/null +++ b/shopinvader_search_engine_image/schemas/__init__.py @@ -0,0 +1,4 @@ +from .image_data import ImageData +from .images_mixin import ImageMixin +from .product_category import ProductCategory +from .product_product import ProductProduct diff --git a/shopinvader_search_engine_image/schemas/image_data.py b/shopinvader_search_engine_image/schemas/image_data.py new file mode 100644 index 0000000000..e69a5ddbeb --- /dev/null +++ b/shopinvader_search_engine_image/schemas/image_data.py @@ -0,0 +1,11 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.extendable_fastapi.schemas import StrictExtendableBaseModel + + +class ImageData(StrictExtendableBaseModel): + sequence: int = 0 + src: str + alt: str = "" + tag: str = "" diff --git a/shopinvader_search_engine_image/schemas/images_mixin.py b/shopinvader_search_engine_image/schemas/images_mixin.py new file mode 100644 index 0000000000..84fd07fb3d --- /dev/null +++ b/shopinvader_search_engine_image/schemas/images_mixin.py @@ -0,0 +1,86 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from pydantic import fields + +from odoo.addons.extendable_fastapi.schemas import StrictExtendableBaseModel +from odoo.addons.search_engine_image_thumbnail.models.se_indexable_record import ( + SeIndexableRecord, +) + +from ..models.se_backend import SeBackend +from .image_data import ImageData + + +class ImageMixin(StrictExtendableBaseModel): + images: list[dict[str, ImageData]] = fields.Field( + default_factory=list, + description="A list of dictionary of image data by image size code." + "The order of the list is the order of the images in the original Odoo " + "record. ", + # fmt: off + # flake8: noqa + examples=[ + [ + { + "small": { + "sequence": 0, + "src": "https://media.alcyonbelux.be/media/" + "table-nac-inox-60-60-222886.jpg", + "alt": "TABLE NAC INOX", + "tag": "", + }, + "large": { + "sequence": 0, + "src": "https://media.alcyonbelux.be/media/" + "table-nac-inox-550-550-222888.jpg", + "alt": "TABLE NAC INOX", + "tag": "", + }, + "medium": { + "sequence": 0, + "src": "https://media.alcyonbelux.be/media/" + "table-nac-inox-300-300-222887.jpg", + "alt": "TABLE NAC INOX", + "tag": "", + }, + } + ] + ], + # fmt: on + ) + + def _fill_image_from_image_relation_mixin( + self, record: SeIndexableRecord, field_name: str + ): + """Fill the images field from a FsImageRelationMixin field.""" + index = record.env["se.index"].browse(record.env.context["index_id"]) + backend: SeBackend = index.backend_id + size_and_thumbnails_by_image = ( + record._get_or_create_thumbnails_for_multi_images( + index=index, field_name=field_name + ) + ) + self.images = [] + cpt = 0 + for ( + image_relation, + size_and_thumbnails, + ) in size_and_thumbnails_by_image.items(): + thumbs = {} + for size, thumbnail in size_and_thumbnails: + tag = "" + if "tag_id" in image_relation._fields: + tag = image_relation.tag_id.name or "" + sequence = cpt + if "sequence" in image_relation._fields: + sequence = image_relation.sequence + thumbs[size.key] = ImageData( + sequence=sequence, + src=backend._get_image_url_for_image(thumbnail.image), + alt=record.name, + tag=tag, + ) + if thumbs: + self.images.append(thumbs) + cpt += 1 diff --git a/shopinvader_search_engine_image/schemas/product_category.py b/shopinvader_search_engine_image/schemas/product_category.py new file mode 100644 index 0000000000..2945712064 --- /dev/null +++ b/shopinvader_search_engine_image/schemas/product_category.py @@ -0,0 +1,14 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.shopinvader_product.schemas import ProductCategory as BaseCategory + +from .images_mixin import ImageMixin + + +class ProductCategory(BaseCategory, ImageMixin, extends=True): + @classmethod + def from_product_category(cls, odoo_rec): + obj = super().from_product_category(odoo_rec) + obj._fill_image_from_image_relation_mixin(odoo_rec, "image_ids") + return obj diff --git a/shopinvader_search_engine_image/schemas/product_product.py b/shopinvader_search_engine_image/schemas/product_product.py new file mode 100644 index 0000000000..085d34b0a1 --- /dev/null +++ b/shopinvader_search_engine_image/schemas/product_product.py @@ -0,0 +1,14 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.addons.shopinvader_product.schemas import ProductProduct as BaseProduct + +from .images_mixin import ImageMixin + + +class ProductProduct(BaseProduct, ImageMixin, extends=True): + @classmethod + def from_product_product(cls, odoo_rec): + obj = super().from_product_product(odoo_rec) + obj._fill_image_from_image_relation_mixin(odoo_rec, "variant_image_ids") + return obj diff --git a/shopinvader_image/static/description/index.html b/shopinvader_search_engine_image/static/description/index.html similarity index 100% rename from shopinvader_image/static/description/index.html rename to shopinvader_search_engine_image/static/description/index.html diff --git a/shopinvader_image/static/img/2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07-524.jpg b/shopinvader_search_engine_image/static/img/2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07-524.jpg similarity index 100% rename from shopinvader_image/static/img/2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07-524.jpg rename to shopinvader_search_engine_image/static/img/2be1238822f7edbc3b3c5f64c6e12f36ec84c861_chathm001gry_uk_thelma_dining_chairs_oak_grey07-524.jpg diff --git a/shopinvader_image/static/img/51gnjksrxml_sl1024_-497.jpg b/shopinvader_search_engine_image/static/img/51gnjksrxml_sl1024_-497.jpg similarity index 100% rename from shopinvader_image/static/img/51gnjksrxml_sl1024_-497.jpg rename to shopinvader_search_engine_image/static/img/51gnjksrxml_sl1024_-497.jpg diff --git a/shopinvader_image/static/img/5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02-515.jpg b/shopinvader_search_engine_image/static/img/5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02-515.jpg similarity index 100% rename from shopinvader_image/static/img/5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02-515.jpg rename to shopinvader_search_engine_image/static/img/5c7f91a29eb6294768ad59bbce80ed04fcaff33d_chathm001gry_uk_thelma_dining_chairs_oak_grey02-515.jpg diff --git a/shopinvader_image/static/img/61kcwirwmjl_sl1500_-289.jpg b/shopinvader_search_engine_image/static/img/61kcwirwmjl_sl1500_-289.jpg similarity index 100% rename from shopinvader_image/static/img/61kcwirwmjl_sl1500_-289.jpg rename to shopinvader_search_engine_image/static/img/61kcwirwmjl_sl1500_-289.jpg diff --git a/shopinvader_image/static/img/61ncsqkegrl_sl1500_-298.jpg b/shopinvader_search_engine_image/static/img/61ncsqkegrl_sl1500_-298.jpg similarity index 100% rename from shopinvader_image/static/img/61ncsqkegrl_sl1500_-298.jpg rename to shopinvader_search_engine_image/static/img/61ncsqkegrl_sl1500_-298.jpg diff --git a/shopinvader_image/static/img/61vffbcilbl_sl1500_-292.jpg b/shopinvader_search_engine_image/static/img/61vffbcilbl_sl1500_-292.jpg similarity index 100% rename from shopinvader_image/static/img/61vffbcilbl_sl1500_-292.jpg rename to shopinvader_search_engine_image/static/img/61vffbcilbl_sl1500_-292.jpg diff --git a/shopinvader_image/static/img/61vvazh7fbl_sl1500_-295.jpg b/shopinvader_search_engine_image/static/img/61vvazh7fbl_sl1500_-295.jpg similarity index 100% rename from shopinvader_image/static/img/61vvazh7fbl_sl1500_-295.jpg rename to shopinvader_search_engine_image/static/img/61vvazh7fbl_sl1500_-295.jpg diff --git a/shopinvader_image/static/img/71c62lnhnxl_sx522_-2.jpg b/shopinvader_search_engine_image/static/img/71c62lnhnxl_sx522_-2.jpg similarity index 100% rename from shopinvader_image/static/img/71c62lnhnxl_sx522_-2.jpg rename to shopinvader_search_engine_image/static/img/71c62lnhnxl_sx522_-2.jpg diff --git a/shopinvader_image/static/img/71ezvti-0l_sx522_-32.jpg b/shopinvader_search_engine_image/static/img/71ezvti-0l_sx522_-32.jpg similarity index 100% rename from shopinvader_image/static/img/71ezvti-0l_sx522_-32.jpg rename to shopinvader_search_engine_image/static/img/71ezvti-0l_sx522_-32.jpg diff --git a/shopinvader_image/static/img/71fudutmpl_sl1500_-310.jpg b/shopinvader_search_engine_image/static/img/71fudutmpl_sl1500_-310.jpg similarity index 100% rename from shopinvader_image/static/img/71fudutmpl_sl1500_-310.jpg rename to shopinvader_search_engine_image/static/img/71fudutmpl_sl1500_-310.jpg diff --git a/shopinvader_image/static/img/71guazzso7l_sl1500_-50.jpg b/shopinvader_search_engine_image/static/img/71guazzso7l_sl1500_-50.jpg similarity index 100% rename from shopinvader_image/static/img/71guazzso7l_sl1500_-50.jpg rename to shopinvader_search_engine_image/static/img/71guazzso7l_sl1500_-50.jpg diff --git a/shopinvader_image/static/img/71gulsoprfl_sl1500_-53.jpg b/shopinvader_search_engine_image/static/img/71gulsoprfl_sl1500_-53.jpg similarity index 100% rename from shopinvader_image/static/img/71gulsoprfl_sl1500_-53.jpg rename to shopinvader_search_engine_image/static/img/71gulsoprfl_sl1500_-53.jpg diff --git a/shopinvader_image/static/img/71qy77hpsgl_sx522_-35.jpg b/shopinvader_search_engine_image/static/img/71qy77hpsgl_sx522_-35.jpg similarity index 100% rename from shopinvader_image/static/img/71qy77hpsgl_sx522_-35.jpg rename to shopinvader_search_engine_image/static/img/71qy77hpsgl_sx522_-35.jpg diff --git a/shopinvader_image/static/img/71r0tdtl1sl_sl1500_-304.jpg b/shopinvader_search_engine_image/static/img/71r0tdtl1sl_sl1500_-304.jpg similarity index 100% rename from shopinvader_image/static/img/71r0tdtl1sl_sl1500_-304.jpg rename to shopinvader_search_engine_image/static/img/71r0tdtl1sl_sl1500_-304.jpg diff --git a/shopinvader_image/static/img/71tq2sgsacl_sl1500_-307.jpg b/shopinvader_search_engine_image/static/img/71tq2sgsacl_sl1500_-307.jpg similarity index 100% rename from shopinvader_image/static/img/71tq2sgsacl_sl1500_-307.jpg rename to shopinvader_search_engine_image/static/img/71tq2sgsacl_sl1500_-307.jpg diff --git a/shopinvader_image/static/img/71uans-wol_sl1500_-313.jpg b/shopinvader_search_engine_image/static/img/71uans-wol_sl1500_-313.jpg similarity index 100% rename from shopinvader_image/static/img/71uans-wol_sl1500_-313.jpg rename to shopinvader_search_engine_image/static/img/71uans-wol_sl1500_-313.jpg diff --git a/shopinvader_image/static/img/71xi8za0npl_sl1500_-301.jpg b/shopinvader_search_engine_image/static/img/71xi8za0npl_sl1500_-301.jpg similarity index 100% rename from shopinvader_image/static/img/71xi8za0npl_sl1500_-301.jpg rename to shopinvader_search_engine_image/static/img/71xi8za0npl_sl1500_-301.jpg diff --git a/shopinvader_image/static/img/73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01-551.jpg b/shopinvader_search_engine_image/static/img/73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01-551.jpg similarity index 100% rename from shopinvader_image/static/img/73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01-551.jpg rename to shopinvader_search_engine_image/static/img/73e214f2ec8bbe6b0687bcc7e53a55b2f70a2a38_chathm006bla_uk_2xthelma_dining_chairs_black_walnut_lb01-551.jpg diff --git a/shopinvader_image/static/img/81c0m6olhjl_sl1500_-131.jpg b/shopinvader_search_engine_image/static/img/81c0m6olhjl_sl1500_-131.jpg similarity index 100% rename from shopinvader_image/static/img/81c0m6olhjl_sl1500_-131.jpg rename to shopinvader_search_engine_image/static/img/81c0m6olhjl_sl1500_-131.jpg diff --git a/shopinvader_image/static/img/81gbmzexsrl_sl1500_-116.jpg b/shopinvader_search_engine_image/static/img/81gbmzexsrl_sl1500_-116.jpg similarity index 100% rename from shopinvader_image/static/img/81gbmzexsrl_sl1500_-116.jpg rename to shopinvader_search_engine_image/static/img/81gbmzexsrl_sl1500_-116.jpg diff --git a/shopinvader_image/static/img/81ggpnkpool_sl1500_-104.jpg b/shopinvader_search_engine_image/static/img/81ggpnkpool_sl1500_-104.jpg similarity index 100% rename from shopinvader_image/static/img/81ggpnkpool_sl1500_-104.jpg rename to shopinvader_search_engine_image/static/img/81ggpnkpool_sl1500_-104.jpg diff --git a/shopinvader_image/static/img/81hd-h2mghl_sl1500_-119.jpg b/shopinvader_search_engine_image/static/img/81hd-h2mghl_sl1500_-119.jpg similarity index 100% rename from shopinvader_image/static/img/81hd-h2mghl_sl1500_-119.jpg rename to shopinvader_search_engine_image/static/img/81hd-h2mghl_sl1500_-119.jpg diff --git a/shopinvader_image/static/img/81ra3tx1yfl_sl1500_-125.jpg b/shopinvader_search_engine_image/static/img/81ra3tx1yfl_sl1500_-125.jpg similarity index 100% rename from shopinvader_image/static/img/81ra3tx1yfl_sl1500_-125.jpg rename to shopinvader_search_engine_image/static/img/81ra3tx1yfl_sl1500_-125.jpg diff --git a/shopinvader_image/static/img/81rt1sqjedl_sl1500_-128.jpg b/shopinvader_search_engine_image/static/img/81rt1sqjedl_sl1500_-128.jpg similarity index 100% rename from shopinvader_image/static/img/81rt1sqjedl_sl1500_-128.jpg rename to shopinvader_search_engine_image/static/img/81rt1sqjedl_sl1500_-128.jpg diff --git a/shopinvader_image/static/img/81ufdwjleal_sl1500_-107.jpg b/shopinvader_search_engine_image/static/img/81ufdwjleal_sl1500_-107.jpg similarity index 100% rename from shopinvader_image/static/img/81ufdwjleal_sl1500_-107.jpg rename to shopinvader_search_engine_image/static/img/81ufdwjleal_sl1500_-107.jpg diff --git a/shopinvader_image/static/img/81wca6qkcul_sl1500_-110.jpg b/shopinvader_search_engine_image/static/img/81wca6qkcul_sl1500_-110.jpg similarity index 100% rename from shopinvader_image/static/img/81wca6qkcul_sl1500_-110.jpg rename to shopinvader_search_engine_image/static/img/81wca6qkcul_sl1500_-110.jpg diff --git a/shopinvader_image/static/img/81zBNebzzNL._SL1500_-122.jpg b/shopinvader_search_engine_image/static/img/81zBNebzzNL._SL1500_-122.jpg similarity index 100% rename from shopinvader_image/static/img/81zBNebzzNL._SL1500_-122.jpg rename to shopinvader_search_engine_image/static/img/81zBNebzzNL._SL1500_-122.jpg diff --git a/shopinvader_image/static/img/91sxta7ujhl_sl1500_-113.jpg b/shopinvader_search_engine_image/static/img/91sxta7ujhl_sl1500_-113.jpg similarity index 100% rename from shopinvader_image/static/img/91sxta7ujhl_sl1500_-113.jpg rename to shopinvader_search_engine_image/static/img/91sxta7ujhl_sl1500_-113.jpg diff --git a/shopinvader_image/static/img/9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03-518.jpg b/shopinvader_search_engine_image/static/img/9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03-518.jpg similarity index 100% rename from shopinvader_image/static/img/9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03-518.jpg rename to shopinvader_search_engine_image/static/img/9affc871da0e733ee523fd6f78fa8d597b4dd25c_chathm001gry_uk_thelma_dining_chairs_oak_grey03-518.jpg diff --git a/shopinvader_image/static/img/c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg-554.png b/shopinvader_search_engine_image/static/img/c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg-554.png similarity index 100% rename from shopinvader_image/static/img/c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg-554.png rename to shopinvader_search_engine_image/static/img/c47c477bc85febd3f99aa3f9c651c02cfa071958_chathm005red_uk_2xthelma_dining_chairs_red_walnut_lb01jpg-554.png diff --git a/shopinvader_image/static/img/g_631993_a-56.jpg b/shopinvader_search_engine_image/static/img/g_631993_a-56.jpg similarity index 100% rename from shopinvader_image/static/img/g_631993_a-56.jpg rename to shopinvader_search_engine_image/static/img/g_631993_a-56.jpg diff --git a/shopinvader_image/static/img/g_631993_c-59.jpg b/shopinvader_search_engine_image/static/img/g_631993_c-59.jpg similarity index 100% rename from shopinvader_image/static/img/g_631993_c-59.jpg rename to shopinvader_search_engine_image/static/img/g_631993_c-59.jpg diff --git a/shopinvader_image/static/img/g_631993_e-65.jpg b/shopinvader_search_engine_image/static/img/g_631993_e-65.jpg similarity index 100% rename from shopinvader_image/static/img/g_631993_e-65.jpg rename to shopinvader_search_engine_image/static/img/g_631993_e-65.jpg diff --git a/shopinvader_image/static/img/g_631993_g-62.jpg b/shopinvader_search_engine_image/static/img/g_631993_g-62.jpg similarity index 100% rename from shopinvader_image/static/img/g_631993_g-62.jpg rename to shopinvader_search_engine_image/static/img/g_631993_g-62.jpg diff --git a/shopinvader_image/static/img/img_20170505_151457-521.jpg b/shopinvader_search_engine_image/static/img/img_20170505_151457-521.jpg similarity index 100% rename from shopinvader_image/static/img/img_20170505_151457-521.jpg rename to shopinvader_search_engine_image/static/img/img_20170505_151457-521.jpg diff --git a/shopinvader_image/static/img/kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk-215.jpg b/shopinvader_search_engine_image/static/img/kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk-215.jpg similarity index 100% rename from shopinvader_image/static/img/kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk-215.jpg rename to shopinvader_search_engine_image/static/img/kitchen-dining-table-white-round-coffee-table-modern-leisure-wooden-tea-table-office-conference-pedestal-desk-215.jpg diff --git a/shopinvader_image/static/img/lux_caritatis_blanc-438.jpg b/shopinvader_search_engine_image/static/img/lux_caritatis_blanc-438.jpg similarity index 100% rename from shopinvader_image/static/img/lux_caritatis_blanc-438.jpg rename to shopinvader_search_engine_image/static/img/lux_caritatis_blanc-438.jpg diff --git a/shopinvader_image/static/img/lux_caritatis_rouge-452.jpg b/shopinvader_search_engine_image/static/img/lux_caritatis_rouge-452.jpg similarity index 100% rename from shopinvader_image/static/img/lux_caritatis_rouge-452.jpg rename to shopinvader_search_engine_image/static/img/lux_caritatis_rouge-452.jpg diff --git a/shopinvader_image/static/img/lux_montis1-444.jpg b/shopinvader_search_engine_image/static/img/lux_montis1-444.jpg similarity index 100% rename from shopinvader_image/static/img/lux_montis1-444.jpg rename to shopinvader_search_engine_image/static/img/lux_montis1-444.jpg diff --git a/shopinvader_image/static/img/lux_montis1-455.jpg b/shopinvader_search_engine_image/static/img/lux_montis1-455.jpg similarity index 100% rename from shopinvader_image/static/img/lux_montis1-455.jpg rename to shopinvader_search_engine_image/static/img/lux_montis1-455.jpg diff --git a/shopinvader_image/static/img/mascara-aloe-vera_748_497-272.jpg b/shopinvader_search_engine_image/static/img/mascara-aloe-vera_748_497-272.jpg similarity index 100% rename from shopinvader_image/static/img/mascara-aloe-vera_748_497-272.jpg rename to shopinvader_search_engine_image/static/img/mascara-aloe-vera_748_497-272.jpg diff --git a/shopinvader_image/static/img/mascara-aloe-vera_748_497-283.png b/shopinvader_search_engine_image/static/img/mascara-aloe-vera_748_497-283.png similarity index 100% rename from shopinvader_image/static/img/mascara-aloe-vera_748_497-283.png rename to shopinvader_search_engine_image/static/img/mascara-aloe-vera_748_497-283.png diff --git a/shopinvader_image/static/img/mascara-aloe-vera_806_535-23.jpg b/shopinvader_search_engine_image/static/img/mascara-aloe-vera_806_535-23.jpg similarity index 100% rename from shopinvader_image/static/img/mascara-aloe-vera_806_535-23.jpg rename to shopinvader_search_engine_image/static/img/mascara-aloe-vera_806_535-23.jpg diff --git a/shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-218.jpg b/shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-218.jpg similarity index 100% rename from shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-218.jpg rename to shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-218.jpg diff --git a/shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-gris-224.jpg b/shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-gris-224.jpg similarity index 100% rename from shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-gris-224.jpg rename to shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-gris-224.jpg diff --git a/shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-221.jpg b/shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-221.jpg similarity index 100% rename from shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-221.jpg rename to shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-221.jpg diff --git a/shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-gris-227.jpg b/shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-gris-227.jpg similarity index 100% rename from shopinvader_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-gris-227.jpg rename to shopinvader_search_engine_image/static/img/meuble-tv-warm-shaker-bois-massif-183cm-scene-gris-227.jpg diff --git a/shopinvader_image/static/img/mid-century-modern-wood-dining-table-natural-side-155.jpg b/shopinvader_search_engine_image/static/img/mid-century-modern-wood-dining-table-natural-side-155.jpg similarity index 100% rename from shopinvader_image/static/img/mid-century-modern-wood-dining-table-natural-side-155.jpg rename to shopinvader_search_engine_image/static/img/mid-century-modern-wood-dining-table-natural-side-155.jpg diff --git a/shopinvader_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-158.jpg b/shopinvader_search_engine_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-158.jpg similarity index 100% rename from shopinvader_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-158.jpg rename to shopinvader_search_engine_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-158.jpg diff --git a/shopinvader_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-close-161.jpg b/shopinvader_search_engine_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-close-161.jpg similarity index 100% rename from shopinvader_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-close-161.jpg rename to shopinvader_search_engine_image/static/img/sauder-420011-coffee-table-furniture-craftsman-oak-close-161.jpg diff --git a/shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-164.jpg b/shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-164.jpg similarity index 100% rename from shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-164.jpg rename to shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-164.jpg diff --git a/shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-167.jpg b/shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-167.jpg similarity index 100% rename from shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-167.jpg rename to shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-167.jpg diff --git a/shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-front-170.jpg b/shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-front-170.jpg similarity index 100% rename from shopinvader_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-front-170.jpg rename to shopinvader_search_engine_image/static/img/sauder-harvey-park-entertainment-credenza-chene-clair-scene-front-170.jpg diff --git a/shopinvader_image/static/img/table-mid-century-natural-wood-152.jpg b/shopinvader_search_engine_image/static/img/table-mid-century-natural-wood-152.jpg similarity index 100% rename from shopinvader_image/static/img/table-mid-century-natural-wood-152.jpg rename to shopinvader_search_engine_image/static/img/table-mid-century-natural-wood-152.jpg diff --git a/shopinvader_image/static/img/table-side-wood-oak-260.jpg b/shopinvader_search_engine_image/static/img/table-side-wood-oak-260.jpg similarity index 100% rename from shopinvader_image/static/img/table-side-wood-oak-260.jpg rename to shopinvader_search_engine_image/static/img/table-side-wood-oak-260.jpg diff --git a/shopinvader_image/static/img/thelma-couple-chair-508.jpg b/shopinvader_search_engine_image/static/img/thelma-couple-chair-508.jpg similarity index 100% rename from shopinvader_image/static/img/thelma-couple-chair-508.jpg rename to shopinvader_search_engine_image/static/img/thelma-couple-chair-508.jpg diff --git a/shopinvader_search_engine_image/tests/__init__.py b/shopinvader_search_engine_image/tests/__init__.py new file mode 100644 index 0000000000..713fc57c0a --- /dev/null +++ b/shopinvader_search_engine_image/tests/__init__.py @@ -0,0 +1 @@ +from . import test_shopinvader_search_engine_image diff --git a/shopinvader_search_engine_image/tests/common.py b/shopinvader_search_engine_image/tests/common.py new file mode 100644 index 0000000000..9c77730657 --- /dev/null +++ b/shopinvader_search_engine_image/tests/common.py @@ -0,0 +1,187 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import base64 +import io + +from odoo_test_helper import FakeModelLoader +from PIL import Image + +from odoo.addons.connector_search_engine.tests.common import TestSeBackendCaseBase +from odoo.addons.extendable.tests.common import ExtendableMixin + + +class TestSeMultiImageThumbnailCase(TestSeBackendCaseBase, ExtendableMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.init_extendable_registry() + cls.loader = FakeModelLoader(cls.env, cls.__module__) + cls.loader.backup_registry() + from odoo.addons.connector_search_engine.tests.models import SeBackend, SeIndex + + cls.loader.update_registry( + ( + SeIndex, + SeBackend, + ) + ) + cls.backend = cls.env["se.backend"].create( + {"name": "Fake SE", "tech_name": "fake_se", "backend_type": "fake"} + ) + + # create thumbnail sizes + cls.size_small = cls.env["se.thumbnail.size"].create( + { + "name": "small", + "key": "small", + "size_x": 5, + "size_y": 5, + } + ) + cls.size_medium = cls.env["se.thumbnail.size"].create( + { + "name": "medium", + "key": "medium", + "size_x": 10, + "size_y": 10, + } + ) + + # create sizes for categories and products + cls.env["se.image.field.thumbnail.size"].create( + { + "model_id": cls.env.ref("product.model_product_product").id, + "field_id": cls.env.ref( + "fs_product_multi_image.field_product_product__variant_image_ids" + ).id, + "backend_id": cls.backend.id, + "size_ids": [(6, 0, [cls.size_small.id, cls.size_medium.id])], + } + ) + + cls.env["se.image.field.thumbnail.size"].create( + { + "model_id": cls.env.ref("product.model_product_category").id, + "field_id": cls.env.ref( + "fs_product_multi_image.field_product_category__image_ids" + ).id, + "backend_id": cls.backend.id, + "size_ids": [(6, 0, [cls.size_small.id, cls.size_medium.id])], + } + ) + + # create image tag + cls.tag1 = cls.env["image.tag"].create( + { + "name": "tag1", + } + ) + cls.tag2 = cls.env["image.tag"].create( + { + "name": "tag2", + } + ) + + # create index for product and category + cls.product_index = cls.env["se.index"].create( + { + "name": "product", + "backend_id": cls.backend.id, + "model_id": cls.env.ref("product.model_product_product").id, + "serializer_type": "shopinvader_product_exports", + } + ) + cls.category_index = cls.env["se.index"].create( + { + "name": "category", + "backend_id": cls.backend.id, + "model_id": cls.env.ref("product.model_product_category").id, + "serializer_type": "shopinvader_category_exports", + } + ) + cls.white_image = cls._create_image(16, 16, color="#FFFFFF") + cls.black_image = cls._create_image(16, 16, color="#000000") + cls.logo_image = cls._create_image(16, 16, color="#FFA500") + cls.product = cls.env["product.product"].create( + { + "name": "Test product", + } + ) + cls.product_white_image = cls.env["fs.product.image"].create( + { + "sequence": 1, + "product_tmpl_id": cls.product.product_tmpl_id.id, + "specific_image": { + "filename": "white.png", + "content": base64.b64encode(cls.white_image), + }, + "tag_id": cls.tag1.id, + } + ) + cls.product_black_image = cls.env["fs.product.image"].create( + { + "sequence": 2, + "product_tmpl_id": cls.product.product_tmpl_id.id, + "specific_image": { + "filename": "black.png", + "content": base64.b64encode(cls.black_image), + }, + "tag_id": cls.tag2.id, + } + ) + cls.product_binding = cls.product._add_to_index(cls.product_index) + + cls.category = cls.env["product.category"].create( + { + "name": "Test category", + } + ) + cls.category_logo_image = cls.env["fs.product.category.image"].create( + { + "sequence": 1, + "product_categ_id": cls.category.id, + "image": { + "filename": "logo.png", + "content": base64.b64encode(cls.logo_image), + }, + } + ) + cls.category_binding = cls.category._add_to_index(cls.category_index) + # set odoo base_url + cls.env["ir.config_parameter"].sudo().set_param( + "web.base.url", "http://localhost:8069" + ) + + def setUp(self): + super().setUp() + # fmt: off + self.fs_storage = self.env["fs.storage"].create( + { + "name": "Temp FS Storage", + "protocol": "memory", + "code": "mem_dir", + "directory_path": "/tmp/", + "model_xmlids": "fs_product_multi_image.model_fs_product_category_image," + "fs_product_multi_image.model_fs_product_image," + "search_engine_image_thumbnail.model_se_thumbnail", + "base_url": "https://media.alcyonbelux.be/", + "is_directory_path_in_url": False, + } + ) + # fmt: on + + @classmethod + def tearDownClass(cls): + cls.loader.restore_registry() + cls.reset_extendable_registry() + super().tearDownClass() + + @classmethod + def _create_image(cls, width, height, color="#4169E1", img_format="PNG"): + f = io.BytesIO() + Image.new("RGB", (width, height), color).save(f, img_format) + f.seek(0) + return f.read() + + def assert_image_size(self, value: bytes, width, height): + self.assertEqual(Image.open(io.BytesIO(value)).size, (width, height)) diff --git a/shopinvader_search_engine_image/tests/test_shopinvader_search_engine_image.py b/shopinvader_search_engine_image/tests/test_shopinvader_search_engine_image.py new file mode 100644 index 0000000000..f0762a9831 --- /dev/null +++ b/shopinvader_search_engine_image/tests/test_shopinvader_search_engine_image.py @@ -0,0 +1,103 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from .common import TestSeMultiImageThumbnailCase + + +class TestShopinvaderSearchEngineImage(TestSeMultiImageThumbnailCase): + def test_product_image(self): + self.backend.image_data_url_strategy = "odoo" + product = self.product_binding._contextualize(self.product_binding) + data = self.product_index.model_serializer.serialize(product.record) + self.assertIn("images", data) + self.assertEqual(len(data["images"]), 2) + # Check the images are sorted by sequence + first_image = data["images"][0] + # we have 2 sizes as key + self.assertEqual(len(first_image), 2) + self.assertEqual(first_image.keys(), {"small", "medium"}) + + # check attributes of the first image + self.assertEqual(first_image["small"]["sequence"], 1) + self.assertEqual(first_image["small"]["tag"], "tag1") + self.assertEqual(first_image["small"]["alt"], self.product.name) + self.assertRegex( + first_image["small"]["src"], + r"\/web/image\/[0-9]+\/test-product_5_5.png", + ) + self.assertRegex( + first_image["medium"]["src"], + r"\/web/image\/[0-9]+\/test-product_10_10.png", + ) + # check attributes of the second image + second_image = data["images"][1] + self.assertEqual(second_image["small"]["sequence"], 2) + self.assertEqual(second_image["small"]["tag"], "tag2") + self.assertEqual(second_image["small"]["alt"], self.product.name) + self.assertRegex( + second_image["small"]["src"], + r"\/web/image\/[0-9]+\/test-product_5_5.png", + ) + self.assertRegex( + second_image["medium"]["src"], + r"\/web/image\/[0-9]+\/test-product_10_10.png", + ) + + def test_product_image_sequence(self): + # we change the sequence of the images + self.product_white_image.sequence = 2 + self.product_black_image.sequence = 1 + # the order into the images field should be different, + # the first image should be the black one with the tag "tag2" + self.backend.image_data_url_strategy = "odoo" + product = self.product_binding._contextualize(self.product_binding) + data = self.product_index.model_serializer.serialize(product.record) + self.assertIn("images", data) + self.assertEqual(len(data["images"]), 2) + # Check the images are sorted by sequence + first_image = data["images"][0] + self.assertEqual(first_image["small"]["sequence"], 1) + self.assertEqual(first_image["small"]["tag"], "tag2") + + second_image = data["images"][1] + self.assertEqual(second_image["small"]["sequence"], 2) + self.assertEqual(second_image["small"]["tag"], "tag1") + + # change sequence again + self.product_white_image.sequence = 1 + self.product_black_image.sequence = 2 + data = self.product_index.model_serializer.serialize(product.record) + first_image = data["images"][0] + self.assertEqual(first_image["small"]["sequence"], 1) + self.assertEqual(first_image["small"]["tag"], "tag1") + + second_image = data["images"][1] + self.assertEqual(second_image["small"]["sequence"], 2) + self.assertEqual(second_image["small"]["tag"], "tag2") + + def test_product_image_src(self): + self.backend.image_data_url_strategy = "odoo" + product = self.product_binding._contextualize(self.product_binding) + data = self.product_index.model_serializer.serialize(product.record) + image = data["images"][0] + self.assertRegex( + image["medium"]["src"], + r"\/web/image\/[0-9]+\/test-product_10_10.png", + ) + + self.backend.image_data_url_strategy = "storage_url" + data = self.product_index.model_serializer.serialize(product.record) + image = data["images"][0] + self.assertRegex( + image["medium"]["src"], + r"https:\/\/media.alcyonbelux.be\/test-product_10_10-[0-9]+-[0-9]+.png", + ) + + self.backend.image_data_url_strategy = "url_path" + data = self.product_index.model_serializer.serialize(product.record) + image = data["images"][0] + self.assertRegex( + image["medium"]["src"], + r"\/test-product_10_10-[0-9]+-[0-9]+.png", + ) diff --git a/shopinvader_search_engine_image/views/se_backend.xml b/shopinvader_search_engine_image/views/se_backend.xml new file mode 100644 index 0000000000..40e01e80e5 --- /dev/null +++ b/shopinvader_search_engine_image/views/se_backend.xml @@ -0,0 +1,14 @@ + + + + + se.backend + + + + + + + + +