diff --git a/conf/nginx/sites-available/obf b/conf/nginx/sites-available/obf index d35c1a027c58d..8a9a302ff9931 100644 --- a/conf/nginx/sites-available/obf +++ b/conf/nginx/sites-available/obf @@ -22,7 +22,7 @@ server { # Product Opener needs a root domain + a wildcard for all subdomains # openbeautyfacts.com is also used for testing - server_name openbeautyfacts.org *.openbeautyfacts.org openbeautyfacts.com *.openbeautyfacts.com; + server_name openbeautyfacts.org *.openbeautyfacts.org; root /srv/obf/html; diff --git a/conf/nginx/sites-available/opf b/conf/nginx/sites-available/opf index 0b2ffde8f65c7..757c3d0213271 100644 --- a/conf/nginx/sites-available/opf +++ b/conf/nginx/sites-available/opf @@ -1,158 +1,135 @@ -## -# You should look at the following URL's in order to grasp a solid understanding -# of Nginx configuration files in order to fully unleash the power of Nginx. -# http://wiki.nginx.org/Pitfalls -# http://wiki.nginx.org/QuickStart -# http://wiki.nginx.org/Configuration +# Default server configuration - nginx_status # -# Generally, you will want to move this file somewhere, and start with a clean -# file but keep this around for reference. Or just disable in sites-enabled. -# -# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. -## - -# Default server configuration -# - - - - server { - listen 80 ; - listen [::]:80 ; - - #listen 443 ssl; - #listen [::]:443 ssl; - - #include snippets/ssl.openproductsfacts.org; - #include snippets/ssl-params.conf; - - - server_name openproductsfacts.org; - return 301 https://world.openproductsfacts.org$request_uri; + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + # nginx_status configuration, need for Munin + location /nginx_status { + stub_status on; + access_log off; + allow all; + } } -include /etc/nginx/snippets/expires-no-json-xml.conf; +# variables definitions for expiry headers are loaded from /etc/nginx/conf.d/expires-no-json-xml.conf server { - #listen 80 default_server; - #listen [::]:80 default_server; + listen 80; listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - - server_name *.openproductsfacts.org openproductsfacts.org; - - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - #listen [::]:443 ssl default_server; - #listen [::]:443 ssl; - include snippets/ssl.openproductsfacts.org; - include snippets/ssl-params.conf; - + # Product Opener needs a root domain + a wildcard for all subdomains + server_name openproductsfacts.org *.openproductsfacts.org; root /srv/opf/html; - access_log /srv/opf/logs/nginx.access2.log; - error_log /srv/opf/logs/nginx.error2.log; + # enable large uploads + client_max_body_size 20M; + client_body_timeout 120s; + client_header_timeout 120s; - # Redirect GET requests to https. POST requests will be transformed - # to GET by most browsers when redirected, and it breaks apps that - # use the API through http. - - if ($scheme = http) { - set $test "A"; - } - if ($request_uri !~ "/api/") { - set $test "${test}B"; - } - if ($request_method = GET) { - set $test "${test}C"; - } - if ($test = ABC) { - return 301 https://$host$request_uri; - } - - location /data/ { - include snippets/off.cors-headers.include; - include snippets/ssl-headers.conf; - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - } + # logs location: default is static-off, will be changed to proxy-opf + # for requests passed to Apache + access_log /var/log/nginx/static-opf-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/static-opf-error.log; + # some redirection for specific subdomains + include snippets/opf.domain-redirects.include; gzip on; gzip_min_length 1000; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript text/csv; - - # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; - location ~* \.(eot|ttf|woff|woff2)$ { - include snippets/off.cors-headers.include; - } - location ~ ^/images/products/ { - add_header Link "; rel='license'; title='CC-BY-SA 3.0'"; include snippets/off.cors-headers.include; include snippets/expiry-headers.include; + add_header Link "; rel='license'; title='CC-BY-SA 3.0'"; # optimize gzip compressed content (like OCR .json stored next to .jpg files) gzip_static always; gunzip on; } + if ($http_referer ~* (jobothoniel.com) ) { return 403; } # blocked since 2021-07-13 + + # the app requests /1.json to get the product count... + # the commented code below is to serve a static copy + # if there is a spike of installs + location ~ ^/1.json$ { + root /srv/opf/html/static; + try_files /1.json = 404; + } + + # Static files are served directly by NGINX + location ~ ^/(favicon.ico) { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } - location ~ ^/(.well-known|images|fonts|css|js|rss|files|resources|foundation|bower_components)/ { + # Static files are served directly by NGINX + location ~ ^/(.well-known|files|data|exports|dump)/ { include snippets/off.cors-headers.include; include snippets/expiry-headers.include; - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; + # First attempt to serve request from resource, then as file, + # then as directory, then fall back to displaying a 404. + try_files resources/$uri $uri $uri/ =404; + gzip_static always; + gunzip on; + } + location ~ ^/(images|fonts|css|js|donate|resources)/ { + include snippets/off.cors-headers.include; + include snippets/expiry-headers.include; + # First attempt to serve request as file, off_web_html acting as an override, + # then as directory, then fall back to displaying a 404. + try_files /off_web_html$uri $uri $uri/ =404; + gzip_static always; + gunzip on; + } + + # Redirect to the change password form + location = /.well-known/change-password { + return 307 https://$host/cgi/change_password.pl; } # GoogleAssociationService made 2500 requests/min to assetlinks.json # and much less when caching headers are sent location = /.well-known/assetlinks.json { - include snippets/off.cors-headers.include; + include snippets/off.cors-headers.include; include snippets/expiry-headers.include; - expires 1d; - try_files $uri $uri/ =404; - } + try_files $uri =404; + } + + include snippets/opf.locations-redirects.include; + + # Dynamically generated files and CGI scripts are passed + # to the Apache + mod_perl server running on a different + # port than port 80 (e.g. 8001) location / { proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # recursive hosts as we are proxying behind a proxy + set_real_ip_from 10.0.0.0/8; + real_ip_recursive on; + access_log /var/log/nginx/proxy-opf-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/proxy-opf-error.log; - proxy_pass http://127.0.0.1:8005/cgi/display.pl?; + proxy_pass http://127.0.0.1:8003/cgi/display.pl?; } location /cgi/ { proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://127.0.0.1:8005; - } + # recursive hosts as we are proxying behind a proxy + set_real_ip_from 10.0.0.0/8; + real_ip_recursive on; + access_log /var/log/nginx/proxy-opf-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/proxy-opf-error.log; - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} + proxy_pass http://127.0.0.1:8003; + } } + diff --git a/conf/nginx/sites-available/opff b/conf/nginx/sites-available/opff index 15ce8ce0385ac..04d115b36cb1f 100644 --- a/conf/nginx/sites-available/opff +++ b/conf/nginx/sites-available/opff @@ -1,160 +1,135 @@ -## -# You should look at the following URL's in order to grasp a solid understanding -# of Nginx configuration files in order to fully unleash the power of Nginx. -# http://wiki.nginx.org/Pitfalls -# http://wiki.nginx.org/QuickStart -# http://wiki.nginx.org/Configuration +# Default server configuration - nginx_status # -# Generally, you will want to move this file somewhere, and start with a clean -# file but keep this around for reference. Or just disable in sites-enabled. -# -# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. -## - -# Default server configuration -# - - - - server { - listen 80 ; - listen [::]:80 ; - - listen 443 ssl; - listen [::]:443 ssl; - - include snippets/ssl.openpetfoodfacts.org; - include snippets/ssl-params-opff.conf; - - - server_name openpetfoodfacts.org; - return 301 https://world.openpetfoodfacts.org$request_uri; + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + # nginx_status configuration, need for Munin + location /nginx_status { + stub_status on; + access_log off; + allow all; + } } -include /etc/nginx/snippets/expires-no-json-xml.conf; +# variables definitions for expiry headers are loaded from /etc/nginx/conf.d/expires-no-json-xml.conf server { - #listen 80 default_server; - #listen [::]:80 default_server; + listen 80; listen [::]:80; - listen 443 ssl; - listen [::]:443 ssl; - - server_name *.openpetfoodfacts.org openpetfoodfacts.eu *.openpetfoodfacts.eu; - - # SSL configuration - # - # listen 443 ssl default_server; - # listen [::]:443 ssl default_server; - # - # Self signed certs generated by the ssl-cert package - # Don't use them in a production server! - # - # include snippets/snakeoil.conf; - #listen [::]:443 ssl default_server; - #listen [::]:443 ssl; - include snippets/ssl.openpetfoodfacts.org; - include snippets/ssl-params-opff.conf; + # Product Opener needs a root domain + a wildcard for all subdomains + server_name openpetfoodfacts.org *.openpetfoodfacts.org; root /srv/opff/html; - access_log /srv/opff/logs/nginx.access2.log; - error_log /srv/opff/logs/nginx.error2.log; - - # Redirect GET requests to https. POST requests will be transformed - # to GET by most browsers when redirected, and it breaks apps that - # use the API through http. - - if ($scheme = http) { - set $test "A"; - } - if ($request_uri !~ "/api/") { - set $test "${test}B"; - } - if ($request_method = GET) { - set $test "${test}C"; - } - if ($test = ABC) { - return 301 https://$host$request_uri; - } - - location /data/ { - include snippets/off.cors-headers.include; - include snippets/expiry-headers.include; - include snippets/ssl-headers.conf; - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; - } + # enable large uploads + client_max_body_size 20M; + client_body_timeout 120s; + client_header_timeout 120s; + + # logs location: default is static-off, will be changed to proxy-opff + # for requests passed to Apache + access_log /var/log/nginx/static-opff-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/static-opff-error.log; + # some redirection for specific subdomains + include snippets/opff.domain-redirects.include; gzip on; gzip_min_length 1000; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript text/csv; - - # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; - location ~* \.(eot|ttf|woff|woff2)$ { - include snippets/off.cors-headers.include; - } - - location ~ ^/images/products/ { - add_header Link "; rel='license'; title='CC-BY-SA 3.0'"; + location ~ ^/images/petfood/ { include snippets/off.cors-headers.include; include snippets/expiry-headers.include; + add_header Link "; rel='license'; title='CC-BY-SA 3.0'"; # optimize gzip compressed content (like OCR .json stored next to .jpg files) gzip_static always; gunzip on; } + if ($http_referer ~* (jobothoniel.com) ) { return 403; } # blocked since 2021-07-13 + + # the app requests /1.json to get the product count... + # the commented code below is to serve a static copy + # if there is a spike of installs + location ~ ^/1.json$ { + root /srv/opff/html/static; + try_files /1.json = 404; + } + + # Static files are served directly by NGINX + location ~ ^/(favicon.ico) { # First attempt to serve request as file, then # as directory, then fall back to displaying a 404. try_files $uri $uri/ =404; } - - location ~ ^/(.well-known|images|fonts|css|js|rss|files|resources|foundation|bower_components)/ { + # Static files are served directly by NGINX + location ~ ^/(.well-known|files|data|exports|dump)/ { include snippets/off.cors-headers.include; include snippets/expiry-headers.include; - # First attempt to serve request as file, then - # as directory, then fall back to displaying a 404. - try_files $uri $uri/ =404; + # First attempt to serve request from resource, then as file, + # then as directory, then fall back to displaying a 404. + try_files resources/$uri $uri $uri/ =404; + gzip_static always; + gunzip on; + } + location ~ ^/(images|fonts|css|js|donate|resources)/ { + include snippets/off.cors-headers.include; + include snippets/expiry-headers.include; + # First attempt to serve request as file, off_web_html acting as an override, + # then as directory, then fall back to displaying a 404. + try_files /off_web_html$uri $uri $uri/ =404; + gzip_static always; + gunzip on; + } + + # Redirect to the change password form + location = /.well-known/change-password { + return 307 https://$host/cgi/change_password.pl; } - # GoogleAssociationService made 2500 requests/min to assetlinks.json - # and much less when caching headers are sent - location = /.well-known/assetlinks.json { - include snippets/off.cors-headers.include; + # GoogleAssociationService made 2500 requests/min to assetlinks.json + # and much less when caching headers are sent + location = /.well-known/assetlinks.json { + include snippets/off.cors-headers.include; include snippets/expiry-headers.include; - expires 1d; - try_files $uri $uri/ =404; - } + try_files $uri =404; + } + + include snippets/opff.locations-redirects.include; + + # Dynamically generated files and CGI scripts are passed + # to the Apache + mod_perl server running on a different + # port than port 80 (e.g. 8001) location / { proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # recursive hosts as we are proxying behind a proxy + set_real_ip_from 10.0.0.0/8; + real_ip_recursive on; + access_log /var/log/nginx/proxy-opff-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/proxy-opff-error.log; - proxy_pass http://127.0.0.1:8004/cgi/display.pl?; + proxy_pass http://127.0.0.1:8001/cgi/display.pl?; } location /cgi/ { proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://127.0.0.1:8004; - } - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} + # recursive hosts as we are proxying behind a proxy + set_real_ip_from 10.0.0.0/8; + real_ip_recursive on; + access_log /var/log/nginx/proxy-opff-access.log proxied_requests buffer=256K flush=1s; + error_log /var/log/nginx/proxy-opff-error.log; + proxy_pass http://127.0.0.1:8001; + } } + diff --git a/conf/nginx/snippets/opf.domain-redirects.include b/conf/nginx/snippets/opf.domain-redirects.include new file mode 100644 index 0000000000000..a617458d492ea --- /dev/null +++ b/conf/nginx/snippets/opf.domain-redirects.include @@ -0,0 +1,2 @@ +# some redirects for opf subdomains that are shortcuts to other places +# currently no subdomains shortcuts are used diff --git a/conf/nginx/snippets/opf.locations-redirects.include b/conf/nginx/snippets/opf.locations-redirects.include new file mode 100644 index 0000000000000..f0d1830dd0df5 --- /dev/null +++ b/conf/nginx/snippets/opf.locations-redirects.include @@ -0,0 +1 @@ +# Redirects for Open Products Facts diff --git a/conf/nginx/snippets/opff.domain-redirects.include b/conf/nginx/snippets/opff.domain-redirects.include new file mode 100644 index 0000000000000..e3103dffc04ea --- /dev/null +++ b/conf/nginx/snippets/opff.domain-redirects.include @@ -0,0 +1,2 @@ +# some redirects for opff subdomains that are shortcuts to other places +# currently no subdomains shortcuts are used diff --git a/conf/nginx/snippets/opff.locations-redirects.include b/conf/nginx/snippets/opff.locations-redirects.include new file mode 100644 index 0000000000000..f2866d675a2a2 --- /dev/null +++ b/conf/nginx/snippets/opff.locations-redirects.include @@ -0,0 +1 @@ +# Redirects for Open Pet Food Facts diff --git a/conf/opf-log.conf b/conf/opf-log.conf new file mode 100644 index 0000000000000..21dda71a5fb4f --- /dev/null +++ b/conf/opf-log.conf @@ -0,0 +1,35 @@ +log4perl.rootLogger=ERROR, LOGFILE +log4perl.logger.mongodb=INFO, MONGODB_LOGFILE +log4perl.logger.ratelimiter=INFO, RATELIMITER_LOGFILE +log4perl.logger.requeststats=INFO, REQUESTSTATS_LOGFILE + +log4perl.PatternLayout.cspec.S = sub { my $context = Log::Log4perl::MDC->get_context; use Data::Dumper (); local $Data::Dumper::Indent = 0; local $Data::Dumper::Terse = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Quotekeys = 0; local $Data::Dumper::Deparse = 1; my $str = Data::Dumper::Dumper($context); $str =~ s/[\n\r]/ /g; return $str; } +log4perl.PatternLayout.cspec.J = sub { my $context = Log::Log4perl::MDC->get_context; use JSON::MaybeXS; my $json_utf8 = JSON::MaybeXS->new->utf8(1)->allow_nonref->canonical; my $str = $json_utf8->encode($context); return $str; } + +log4perl.appender.LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.LOGFILE.filename=/srv/opf/logs/log4perl.log +log4perl.appender.LOGFILE.mode=append +log4perl.appender.LOGFILE.autoflush=1 +log4perl.appender.LOGFILE.layout=PatternLayout +log4perl.appender.LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.MONGODB_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.MONGODB_LOGFILE.filename=/srv/opf/logs/mongodb_log4perl.log +log4perl.appender.MONGODB_LOGFILE.mode=append +log4perl.appender.MONGODB_LOGFILE.autoflush=1 +log4perl.appender.MONGODB_LOGFILE.layout=PatternLayout +log4perl.appender.MONGODB_LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.RATELIMITER_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.RATELIMITER_LOGFILE.filename=/srv/opf/logs/ratelimiter_log4perl.log +log4perl.appender.RATELIMITER_LOGFILE.mode=append +log4perl.appender.RATELIMITER_LOGFILE.autoflush=1 +log4perl.appender.RATELIMITER_LOGFILE.layout=PatternLayout +log4perl.appender.RATELIMITER_LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.REQUESTSTATS_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.REQUESTSTATS_LOGFILE.filename=/srv/opf/logs/requeststats_log4perl.log +log4perl.appender.REQUESTSTATS_LOGFILE.mode=append +log4perl.appender.REQUESTSTATS_LOGFILE.autoflush=1 +log4perl.appender.REQUESTSTATS_LOGFILE.layout=PatternLayout +log4perl.appender.REQUESTSTATS_LOGFILE.layout.ConversionPattern=%J %n diff --git a/conf/opff-log.conf b/conf/opff-log.conf new file mode 100644 index 0000000000000..e96eb118b60e5 --- /dev/null +++ b/conf/opff-log.conf @@ -0,0 +1,35 @@ +log4perl.rootLogger=ERROR, LOGFILE +log4perl.logger.mongodb=INFO, MONGODB_LOGFILE +log4perl.logger.ratelimiter=INFO, RATELIMITER_LOGFILE +log4perl.logger.requeststats=INFO, REQUESTSTATS_LOGFILE + +log4perl.PatternLayout.cspec.S = sub { my $context = Log::Log4perl::MDC->get_context; use Data::Dumper (); local $Data::Dumper::Indent = 0; local $Data::Dumper::Terse = 1; local $Data::Dumper::Sortkeys = 1; local $Data::Dumper::Quotekeys = 0; local $Data::Dumper::Deparse = 1; my $str = Data::Dumper::Dumper($context); $str =~ s/[\n\r]/ /g; return $str; } +log4perl.PatternLayout.cspec.J = sub { my $context = Log::Log4perl::MDC->get_context; use JSON::MaybeXS; my $json_utf8 = JSON::MaybeXS->new->utf8(1)->allow_nonref->canonical; my $str = $json_utf8->encode($context); return $str; } + +log4perl.appender.LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.LOGFILE.filename=/srv/opff/logs/log4perl.log +log4perl.appender.LOGFILE.mode=append +log4perl.appender.LOGFILE.autoflush=1 +log4perl.appender.LOGFILE.layout=PatternLayout +log4perl.appender.LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.MONGODB_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.MONGODB_LOGFILE.filename=/srv/opff/logs/mongodb_log4perl.log +log4perl.appender.MONGODB_LOGFILE.mode=append +log4perl.appender.MONGODB_LOGFILE.autoflush=1 +log4perl.appender.MONGODB_LOGFILE.layout=PatternLayout +log4perl.appender.MONGODB_LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.RATELIMITER_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.RATELIMITER_LOGFILE.filename=/srv/opff/logs/ratelimiter_log4perl.log +log4perl.appender.RATELIMITER_LOGFILE.mode=append +log4perl.appender.RATELIMITER_LOGFILE.autoflush=1 +log4perl.appender.RATELIMITER_LOGFILE.layout=PatternLayout +log4perl.appender.RATELIMITER_LOGFILE.layout.ConversionPattern=[%d] %F %L %c %S %m{chomp}%n + +log4perl.appender.REQUESTSTATS_LOGFILE=Log::Log4perl::Appender::File +log4perl.appender.REQUESTSTATS_LOGFILE.filename=/srv/opff/logs/requeststats_log4perl.log +log4perl.appender.REQUESTSTATS_LOGFILE.mode=append +log4perl.appender.REQUESTSTATS_LOGFILE.autoflush=1 +log4perl.appender.REQUESTSTATS_LOGFILE.layout=PatternLayout +log4perl.appender.REQUESTSTATS_LOGFILE.layout.ConversionPattern=%J %n diff --git a/html/images/favicon/obf/android-chrome-192x192.png b/html/images/favicon/obf/android-chrome-192x192.png new file mode 100644 index 0000000000000..1cdf4ccc6c9f2 Binary files /dev/null and b/html/images/favicon/obf/android-chrome-192x192.png differ diff --git a/html/images/favicon/obf/android-chrome-512x512.png b/html/images/favicon/obf/android-chrome-512x512.png new file mode 100644 index 0000000000000..5cde3761f0366 Binary files /dev/null and b/html/images/favicon/obf/android-chrome-512x512.png differ diff --git a/html/images/favicon/obf/apple-touch-icon.png b/html/images/favicon/obf/apple-touch-icon.png new file mode 100644 index 0000000000000..323653091d886 Binary files /dev/null and b/html/images/favicon/obf/apple-touch-icon.png differ diff --git a/html/images/favicon/obf/browserconfig.xml b/html/images/favicon/obf/browserconfig.xml new file mode 100644 index 0000000000000..166be7c1a43e1 --- /dev/null +++ b/html/images/favicon/obf/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #2b5797 + + + diff --git a/html/images/favicon/obf/favicon-16x16.png b/html/images/favicon/obf/favicon-16x16.png new file mode 100644 index 0000000000000..43f0d17852779 Binary files /dev/null and b/html/images/favicon/obf/favicon-16x16.png differ diff --git a/html/images/favicon/obf/favicon-32x32.png b/html/images/favicon/obf/favicon-32x32.png new file mode 100644 index 0000000000000..bd6b006593312 Binary files /dev/null and b/html/images/favicon/obf/favicon-32x32.png differ diff --git a/html/images/favicon/obf/favicon.ico b/html/images/favicon/obf/favicon.ico new file mode 100644 index 0000000000000..d347b4287dfa1 Binary files /dev/null and b/html/images/favicon/obf/favicon.ico differ diff --git a/html/images/favicon/obf/mstile-144x144.png b/html/images/favicon/obf/mstile-144x144.png new file mode 100644 index 0000000000000..5c88a90b9c0fa Binary files /dev/null and b/html/images/favicon/obf/mstile-144x144.png differ diff --git a/html/images/favicon/obf/mstile-150x150.png b/html/images/favicon/obf/mstile-150x150.png new file mode 100644 index 0000000000000..01f2bdc647457 Binary files /dev/null and b/html/images/favicon/obf/mstile-150x150.png differ diff --git a/html/images/favicon/obf/mstile-310x150.png b/html/images/favicon/obf/mstile-310x150.png new file mode 100644 index 0000000000000..bdd2d90607c62 Binary files /dev/null and b/html/images/favicon/obf/mstile-310x150.png differ diff --git a/html/images/favicon/obf/mstile-310x310.png b/html/images/favicon/obf/mstile-310x310.png new file mode 100644 index 0000000000000..8a7b9641a4689 Binary files /dev/null and b/html/images/favicon/obf/mstile-310x310.png differ diff --git a/html/images/favicon/obf/mstile-70x70.png b/html/images/favicon/obf/mstile-70x70.png new file mode 100644 index 0000000000000..18b03b025242f Binary files /dev/null and b/html/images/favicon/obf/mstile-70x70.png differ diff --git a/html/images/favicon/obf/safari-pinned-tab.svg b/html/images/favicon/obf/safari-pinned-tab.svg new file mode 100644 index 0000000000000..8f83bc8544780 --- /dev/null +++ b/html/images/favicon/obf/safari-pinned-tab.svg @@ -0,0 +1,27 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/html/images/favicon/obf/site.webmanifest b/html/images/favicon/obf/site.webmanifest new file mode 100644 index 0000000000000..463dcd0701a80 --- /dev/null +++ b/html/images/favicon/obf/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Open BeautyFood Facts", + "short_name": "Open BeautyFood Facts", + "icons": [ + { + "src": "/images/favicon/obf/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/favicon/obf/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/html/images/favicon/off/android-chrome-192x192.png b/html/images/favicon/off/android-chrome-192x192.png new file mode 100644 index 0000000000000..9f7a3f1a4d361 Binary files /dev/null and b/html/images/favicon/off/android-chrome-192x192.png differ diff --git a/html/images/favicon/off/android-chrome-512x512.png b/html/images/favicon/off/android-chrome-512x512.png new file mode 100644 index 0000000000000..2e865aab43121 Binary files /dev/null and b/html/images/favicon/off/android-chrome-512x512.png differ diff --git a/html/images/favicon/off/apple-touch-icon.png b/html/images/favicon/off/apple-touch-icon.png new file mode 100644 index 0000000000000..5ffd362618cfa Binary files /dev/null and b/html/images/favicon/off/apple-touch-icon.png differ diff --git a/html/images/favicon/off/browserconfig.xml b/html/images/favicon/off/browserconfig.xml new file mode 100644 index 0000000000000..31e2720ce8a9c --- /dev/null +++ b/html/images/favicon/off/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #00aba9 + + + diff --git a/html/images/favicon/off/favicon-16x16.png b/html/images/favicon/off/favicon-16x16.png new file mode 100644 index 0000000000000..145bdde31648f Binary files /dev/null and b/html/images/favicon/off/favicon-16x16.png differ diff --git a/html/images/favicon/off/favicon-32x32.png b/html/images/favicon/off/favicon-32x32.png new file mode 100644 index 0000000000000..6b4602a37083f Binary files /dev/null and b/html/images/favicon/off/favicon-32x32.png differ diff --git a/html/images/favicon/off/favicon.ico b/html/images/favicon/off/favicon.ico new file mode 100644 index 0000000000000..6f2cabb4865d0 Binary files /dev/null and b/html/images/favicon/off/favicon.ico differ diff --git a/html/images/favicon/off/mstile-144x144.png b/html/images/favicon/off/mstile-144x144.png new file mode 100644 index 0000000000000..3176563a6ca0b Binary files /dev/null and b/html/images/favicon/off/mstile-144x144.png differ diff --git a/html/images/favicon/off/mstile-150x150.png b/html/images/favicon/off/mstile-150x150.png new file mode 100644 index 0000000000000..6a5ea13018be1 Binary files /dev/null and b/html/images/favicon/off/mstile-150x150.png differ diff --git a/html/images/favicon/off/mstile-310x150.png b/html/images/favicon/off/mstile-310x150.png new file mode 100644 index 0000000000000..df66102f7f605 Binary files /dev/null and b/html/images/favicon/off/mstile-310x150.png differ diff --git a/html/images/favicon/off/mstile-310x310.png b/html/images/favicon/off/mstile-310x310.png new file mode 100644 index 0000000000000..da4de9e2c5403 Binary files /dev/null and b/html/images/favicon/off/mstile-310x310.png differ diff --git a/html/images/favicon/off/mstile-70x70.png b/html/images/favicon/off/mstile-70x70.png new file mode 100644 index 0000000000000..4e7b64a92c410 Binary files /dev/null and b/html/images/favicon/off/mstile-70x70.png differ diff --git a/html/images/favicon/off/safari-pinned-tab.svg b/html/images/favicon/off/safari-pinned-tab.svg new file mode 100644 index 0000000000000..666675ab74e52 --- /dev/null +++ b/html/images/favicon/off/safari-pinned-tab.svg @@ -0,0 +1,27 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/html/images/favicon/off/site.webmanifest b/html/images/favicon/off/site.webmanifest new file mode 100644 index 0000000000000..530a39467faa9 --- /dev/null +++ b/html/images/favicon/off/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Open Food Facts", + "short_name": "Open Food Facts", + "icons": [ + { + "src": "/images/favicon/off/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/favicon/off/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/html/images/favicon/opf/android-chrome-192x192.png b/html/images/favicon/opf/android-chrome-192x192.png new file mode 100644 index 0000000000000..82da70024ce94 Binary files /dev/null and b/html/images/favicon/opf/android-chrome-192x192.png differ diff --git a/html/images/favicon/opf/android-chrome-512x512.png b/html/images/favicon/opf/android-chrome-512x512.png new file mode 100644 index 0000000000000..5d89aa63d36f7 Binary files /dev/null and b/html/images/favicon/opf/android-chrome-512x512.png differ diff --git a/html/images/favicon/opf/apple-touch-icon.png b/html/images/favicon/opf/apple-touch-icon.png new file mode 100644 index 0000000000000..72f8dbb08bab7 Binary files /dev/null and b/html/images/favicon/opf/apple-touch-icon.png differ diff --git a/html/images/favicon/opf/browserconfig.xml b/html/images/favicon/opf/browserconfig.xml new file mode 100644 index 0000000000000..67823743c694a --- /dev/null +++ b/html/images/favicon/opf/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #00aba9 + + + diff --git a/html/images/favicon/opf/favicon-16x16.png b/html/images/favicon/opf/favicon-16x16.png new file mode 100644 index 0000000000000..677dc54de57d1 Binary files /dev/null and b/html/images/favicon/opf/favicon-16x16.png differ diff --git a/html/images/favicon/opf/favicon-32x32.png b/html/images/favicon/opf/favicon-32x32.png new file mode 100644 index 0000000000000..89e64a2fda13d Binary files /dev/null and b/html/images/favicon/opf/favicon-32x32.png differ diff --git a/html/images/favicon/opf/favicon.ico b/html/images/favicon/opf/favicon.ico new file mode 100644 index 0000000000000..05258abc6a381 Binary files /dev/null and b/html/images/favicon/opf/favicon.ico differ diff --git a/html/images/favicon/opf/mstile-144x144.png b/html/images/favicon/opf/mstile-144x144.png new file mode 100644 index 0000000000000..2f02b5acc6def Binary files /dev/null and b/html/images/favicon/opf/mstile-144x144.png differ diff --git a/html/images/favicon/opf/mstile-150x150.png b/html/images/favicon/opf/mstile-150x150.png new file mode 100644 index 0000000000000..0ab1a9fe1ff0c Binary files /dev/null and b/html/images/favicon/opf/mstile-150x150.png differ diff --git a/html/images/favicon/opf/mstile-310x150.png b/html/images/favicon/opf/mstile-310x150.png new file mode 100644 index 0000000000000..2099726d3f1b2 Binary files /dev/null and b/html/images/favicon/opf/mstile-310x150.png differ diff --git a/html/images/favicon/opf/mstile-310x310.png b/html/images/favicon/opf/mstile-310x310.png new file mode 100644 index 0000000000000..2a759d8f809e4 Binary files /dev/null and b/html/images/favicon/opf/mstile-310x310.png differ diff --git a/html/images/favicon/opf/mstile-70x70.png b/html/images/favicon/opf/mstile-70x70.png new file mode 100644 index 0000000000000..da590f215b56b Binary files /dev/null and b/html/images/favicon/opf/mstile-70x70.png differ diff --git a/html/images/favicon/opf/safari-pinned-tab.svg b/html/images/favicon/opf/safari-pinned-tab.svg new file mode 100644 index 0000000000000..3b8fd5864f200 --- /dev/null +++ b/html/images/favicon/opf/safari-pinned-tab.svg @@ -0,0 +1,30 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/html/images/favicon/opf/site.webmanifest b/html/images/favicon/opf/site.webmanifest new file mode 100644 index 0000000000000..c84b08358dd5f --- /dev/null +++ b/html/images/favicon/opf/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/images/favicon/opf/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/favicon/opf/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/html/images/favicon/opff/android-chrome-192x192.png b/html/images/favicon/opff/android-chrome-192x192.png new file mode 100644 index 0000000000000..ac99b1f146c95 Binary files /dev/null and b/html/images/favicon/opff/android-chrome-192x192.png differ diff --git a/html/images/favicon/opff/android-chrome-512x512.png b/html/images/favicon/opff/android-chrome-512x512.png new file mode 100644 index 0000000000000..8ce895c3b2b7c Binary files /dev/null and b/html/images/favicon/opff/android-chrome-512x512.png differ diff --git a/html/images/favicon/opff/apple-touch-icon.png b/html/images/favicon/opff/apple-touch-icon.png new file mode 100644 index 0000000000000..1c7f017c4d303 Binary files /dev/null and b/html/images/favicon/opff/apple-touch-icon.png differ diff --git a/html/images/favicon/opff/browserconfig.xml b/html/images/favicon/opff/browserconfig.xml new file mode 100644 index 0000000000000..96031cf6a70c4 --- /dev/null +++ b/html/images/favicon/opff/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #00aba9 + + + diff --git a/html/images/favicon/opff/favicon-16x16.png b/html/images/favicon/opff/favicon-16x16.png new file mode 100644 index 0000000000000..832567b333753 Binary files /dev/null and b/html/images/favicon/opff/favicon-16x16.png differ diff --git a/html/images/favicon/opff/favicon-32x32.png b/html/images/favicon/opff/favicon-32x32.png new file mode 100644 index 0000000000000..629153cefeca5 Binary files /dev/null and b/html/images/favicon/opff/favicon-32x32.png differ diff --git a/html/images/favicon/opff/favicon.ico b/html/images/favicon/opff/favicon.ico new file mode 100644 index 0000000000000..e35058b8f0779 Binary files /dev/null and b/html/images/favicon/opff/favicon.ico differ diff --git a/html/images/favicon/opff/mstile-144x144.png b/html/images/favicon/opff/mstile-144x144.png new file mode 100644 index 0000000000000..49be362ee6184 Binary files /dev/null and b/html/images/favicon/opff/mstile-144x144.png differ diff --git a/html/images/favicon/opff/mstile-150x150.png b/html/images/favicon/opff/mstile-150x150.png new file mode 100644 index 0000000000000..82bef1ab81b85 Binary files /dev/null and b/html/images/favicon/opff/mstile-150x150.png differ diff --git a/html/images/favicon/opff/mstile-310x150.png b/html/images/favicon/opff/mstile-310x150.png new file mode 100644 index 0000000000000..c0aa393e6c3dc Binary files /dev/null and b/html/images/favicon/opff/mstile-310x150.png differ diff --git a/html/images/favicon/opff/mstile-310x310.png b/html/images/favicon/opff/mstile-310x310.png new file mode 100644 index 0000000000000..e4f95af4487b3 Binary files /dev/null and b/html/images/favicon/opff/mstile-310x310.png differ diff --git a/html/images/favicon/opff/mstile-70x70.png b/html/images/favicon/opff/mstile-70x70.png new file mode 100644 index 0000000000000..44bc8c030504c Binary files /dev/null and b/html/images/favicon/opff/mstile-70x70.png differ diff --git a/html/images/favicon/opff/safari-pinned-tab.svg b/html/images/favicon/opff/safari-pinned-tab.svg new file mode 100644 index 0000000000000..56621fce64a34 --- /dev/null +++ b/html/images/favicon/opff/safari-pinned-tab.svg @@ -0,0 +1,44 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + + + diff --git a/html/images/favicon/opff/site.webmanifest b/html/images/favicon/opff/site.webmanifest new file mode 100644 index 0000000000000..ac545879839f8 --- /dev/null +++ b/html/images/favicon/opff/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "Open Pet Food Facts", + "short_name": "Open Pet Food Facts", + "icons": [ + { + "src": "/images/favicon/opff/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/favicon/opff/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/html/images/favicon/readme.md b/html/images/favicon/readme.md new file mode 100644 index 0000000000000..90a4d4d8d5fda --- /dev/null +++ b/html/images/favicon/readme.md @@ -0,0 +1 @@ +Icons generated with https://realfavicongenerator.net/ using the SVG icon diff --git a/html/images/lang/fr/labels/indice-de-durabilite-inconnu.108x90.svg b/html/images/lang/fr/labels/indice-de-durabilite-inconnu.108x90.svg new file mode 100644 index 0000000000000..ab42c509753bf --- /dev/null +++ b/html/images/lang/fr/labels/indice-de-durabilite-inconnu.108x90.svg @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/lang/fr/labels/indice-de-durabilite-non-applicable.108x90.svg b/html/images/lang/fr/labels/indice-de-durabilite-non-applicable.108x90.svg new file mode 100644 index 0000000000000..6b8ae641466e0 --- /dev/null +++ b/html/images/lang/fr/labels/indice-de-durabilite-non-applicable.108x90.svg @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/lang/fr/labels/indice-de-reparabilite-inconnu.152x90.svg b/html/images/lang/fr/labels/indice-de-reparabilite-inconnu.152x90.svg new file mode 100644 index 0000000000000..4a4a108e9fa8c --- /dev/null +++ b/html/images/lang/fr/labels/indice-de-reparabilite-inconnu.152x90.svg @@ -0,0 +1,1125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/lang/fr/labels/indice-de-reparabilite-non-applicable.152x90.svg b/html/images/lang/fr/labels/indice-de-reparabilite-non-applicable.152x90.svg new file mode 100644 index 0000000000000..d16d3abc48758 --- /dev/null +++ b/html/images/lang/fr/labels/indice-de-reparabilite-non-applicable.152x90.svg @@ -0,0 +1,1134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-favicon-light.png b/html/images/logos/opf-logo-favicon-light.png new file mode 100644 index 0000000000000..467879ce0939e Binary files /dev/null and b/html/images/logos/opf-logo-favicon-light.png differ diff --git a/html/images/logos/opf-logo-horizontal-dark.svg b/html/images/logos/opf-logo-horizontal-dark.svg new file mode 100644 index 0000000000000..0ce3f4bac2e8f --- /dev/null +++ b/html/images/logos/opf-logo-horizontal-dark.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-horizontal-light.svg b/html/images/logos/opf-logo-horizontal-light.svg new file mode 100644 index 0000000000000..85e6cbf389154 --- /dev/null +++ b/html/images/logos/opf-logo-horizontal-light.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-horizontal-mono-black.svg b/html/images/logos/opf-logo-horizontal-mono-black.svg new file mode 100644 index 0000000000000..dec35d269c079 --- /dev/null +++ b/html/images/logos/opf-logo-horizontal-mono-black.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-horizontal-mono-white.svg b/html/images/logos/opf-logo-horizontal-mono-white.svg new file mode 100644 index 0000000000000..4eddb3859334d --- /dev/null +++ b/html/images/logos/opf-logo-horizontal-mono-white.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-icon-dark.svg b/html/images/logos/opf-logo-icon-dark.svg new file mode 100644 index 0000000000000..f887ba9dbfc7f --- /dev/null +++ b/html/images/logos/opf-logo-icon-dark.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-icon-light.svg b/html/images/logos/opf-logo-icon-light.svg new file mode 100644 index 0000000000000..399d3eb3ee209 --- /dev/null +++ b/html/images/logos/opf-logo-icon-light.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-vertical-dark.svg b/html/images/logos/opf-logo-vertical-dark.svg new file mode 100644 index 0000000000000..36dc7a16da61a --- /dev/null +++ b/html/images/logos/opf-logo-vertical-dark.svg @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opf-logo-vertical-light.svg b/html/images/logos/opf-logo-vertical-light.svg new file mode 100644 index 0000000000000..d34c55f9356d1 --- /dev/null +++ b/html/images/logos/opf-logo-vertical-light.svg @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-favicon-light.png b/html/images/logos/opff-logo-favicon-light.png new file mode 100644 index 0000000000000..df51457fe622d Binary files /dev/null and b/html/images/logos/opff-logo-favicon-light.png differ diff --git a/html/images/logos/opff-logo-horizontal-dark.svg b/html/images/logos/opff-logo-horizontal-dark.svg new file mode 100644 index 0000000000000..b6e0bcb6927ea --- /dev/null +++ b/html/images/logos/opff-logo-horizontal-dark.svg @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-horizontal-light.svg b/html/images/logos/opff-logo-horizontal-light.svg new file mode 100644 index 0000000000000..1eaccdbff0b95 --- /dev/null +++ b/html/images/logos/opff-logo-horizontal-light.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-horizontal-mono-black.svg b/html/images/logos/opff-logo-horizontal-mono-black.svg new file mode 100644 index 0000000000000..ffbdc57ff2e96 --- /dev/null +++ b/html/images/logos/opff-logo-horizontal-mono-black.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-horizontal-mono-white.svg b/html/images/logos/opff-logo-horizontal-mono-white.svg new file mode 100644 index 0000000000000..1faa52283654a --- /dev/null +++ b/html/images/logos/opff-logo-horizontal-mono-white.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-icon-dark.svg b/html/images/logos/opff-logo-icon-dark.svg new file mode 100644 index 0000000000000..8dee2d30cf700 --- /dev/null +++ b/html/images/logos/opff-logo-icon-dark.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-icon-light.svg b/html/images/logos/opff-logo-icon-light.svg new file mode 100644 index 0000000000000..e2dee29ffba39 --- /dev/null +++ b/html/images/logos/opff-logo-icon-light.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-vertical-dark.svg b/html/images/logos/opff-logo-vertical-dark.svg new file mode 100644 index 0000000000000..2820a83b6dc5d --- /dev/null +++ b/html/images/logos/opff-logo-vertical-dark.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/logos/opff-logo-vertical-light.svg b/html/images/logos/opff-logo-vertical-light.svg new file mode 100644 index 0000000000000..06bfa3d8eb91a --- /dev/null +++ b/html/images/logos/opff-logo-vertical-light.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/html/images/panels/fr-impact-co2/ademe.svg b/html/images/panels/fr-impact-co2/ademe.svg new file mode 100644 index 0000000000000..8bdb609ce75f5 --- /dev/null +++ b/html/images/panels/fr-impact-co2/ademe.svg @@ -0,0 +1 @@ + diff --git a/html/images/panels/fr-impact-co2/impact-co2.svg b/html/images/panels/fr-impact-co2/impact-co2.svg new file mode 100644 index 0000000000000..22cd8d2cebfdf --- /dev/null +++ b/html/images/panels/fr-impact-co2/impact-co2.svg @@ -0,0 +1 @@ + diff --git a/html/images/panels/fr-impact-co2/republique-francaise-ademe-impact-co2.svg b/html/images/panels/fr-impact-co2/republique-francaise-ademe-impact-co2.svg new file mode 100644 index 0000000000000..7ddd1d4579347 --- /dev/null +++ b/html/images/panels/fr-impact-co2/republique-francaise-ademe-impact-co2.svg @@ -0,0 +1,295 @@ + + + + diff --git a/html/images/panels/fr-impact-co2/republique-francaise.svg b/html/images/panels/fr-impact-co2/republique-francaise.svg new file mode 100644 index 0000000000000..6a47255d15252 --- /dev/null +++ b/html/images/panels/fr-impact-co2/republique-francaise.svg @@ -0,0 +1,2 @@ + + diff --git a/html/images/panels/secondhand/backmarket.200x100.svg b/html/images/panels/secondhand/backmarket.200x100.svg new file mode 100644 index 0000000000000..423a1fe8c80dc --- /dev/null +++ b/html/images/panels/secondhand/backmarket.200x100.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + diff --git a/html/images/panels/secondhand/backmarket.svg b/html/images/panels/secondhand/backmarket.svg new file mode 100644 index 0000000000000..990ccaea4f49c --- /dev/null +++ b/html/images/panels/secondhand/backmarket.svg @@ -0,0 +1 @@ + diff --git a/html/images/panels/secondhand/geev.200x100.svg b/html/images/panels/secondhand/geev.200x100.svg new file mode 100644 index 0000000000000..93a5fb431251b --- /dev/null +++ b/html/images/panels/secondhand/geev.200x100.svg @@ -0,0 +1,44 @@ + + + + diff --git a/html/images/panels/secondhand/geev.svg b/html/images/panels/secondhand/geev.svg new file mode 100644 index 0000000000000..e35bc5995f78e --- /dev/null +++ b/html/images/panels/secondhand/geev.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/html/js/product-preferences.js b/html/js/product-preferences.js index 450bdf5433060..b8c12dd987e78 100644 --- a/html/js/product-preferences.js +++ b/html/js/product-preferences.js @@ -1,10 +1,10 @@ /*global lang */ /*global preferences_text*/ // depends on which type of page the preferences are shown on +/*global default_preferences*/ // depends on flavor: OFF, OBF etc. var attribute_groups; // All supported attribute groups and attributes + translated strings var preferences; // All supported preferences + translated strings var use_user_product_preferences_for_ranking = JSON.parse(localStorage.getItem('use_user_product_preferences_for_ranking')); -var default_preferences = { "nutriscore" : "very_important", "nova" : "important", "ecoscore" : "important" }; function get_user_product_preferences() { // Retrieve user preferences from local storage @@ -127,7 +127,7 @@ function display_use_preferences_switch_and_edit_preferences_button(target_selec var html_edit_preferences = '
' + '' + - " " + lang().preferences_edit_your_food_preferences + '
'; + " " + lang().preferences_edit_your_preferences + ''; // Display a switch for scoring and ranking products according to the user preferences @@ -252,7 +252,7 @@ function display_user_product_preferences(target_selected, target_selection_form + '' + '' + " " + lang().close + '' - + "

" + lang().preferences_edit_your_food_preferences + "

" + + "

" + lang().preferences_edit_your_preferences + "

" + "

" + lang().preferences_locally_saved + "

" + generate_preferences_switch_button(lang().classify_products_according_to_your_preferences, "preferences_switch_in_preferences") + '' + lang().reset_preferences + '' diff --git a/lib/ProductOpener/Attributes.pm b/lib/ProductOpener/Attributes.pm index d6183d9272699..0fb4b8fba081c 100644 --- a/lib/ProductOpener/Attributes.pm +++ b/lib/ProductOpener/Attributes.pm @@ -61,13 +61,15 @@ use vars @EXPORT_OK; use ProductOpener::Config qw/:all/; use ProductOpener::Store qw/:all/; -use ProductOpener::Tags qw/%level display_taxonomy_tag display_taxonomy_tag_name has_tag/; +use ProductOpener::Tags + qw/%level display_taxonomy_tag display_taxonomy_tag_name has_tag get_inherited_property_from_tags/; use ProductOpener::Products qw/:all/; use ProductOpener::Food qw/@nutrient_levels/; use ProductOpener::Ingredients qw/:all/; use ProductOpener::Lang qw/f_lang_in_lc lang lang_in_other_lc/; use ProductOpener::Display qw/$static_subdomain/; use ProductOpener::Ecoscore qw/:all/; +use ProductOpener::ProductsFeatures qw/feature_enabled/; use Data::DeepAccess qw(deep_get); @@ -96,9 +98,15 @@ $options{attribute_groups} = [ # Build a hash of attribute groups to make it easier to retrieve all attributes of a specific group my %attribute_groups = (); +# Build a hash of attributes to make it easier to retrieve all attributes +my %attributes = (); + if (defined $options{attribute_groups}) { foreach my $attribute_group_ref (@{$options{attribute_groups}}) { $attribute_groups{$attribute_group_ref->[0]} = $attribute_group_ref->[1]; + foreach my $attribute_id (@{$attribute_group_ref->[1]}) { + $attributes{$attribute_id} = 1; + } } } @@ -306,6 +314,9 @@ sub initialize_attribute ($attribute_id, $target_lc) { $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/${tag}.svg"; } + elsif ($attribute_id eq "repairability_index_france") { + $attribute_ref->{icon_url} = "$static_subdomain/images/lang/fr/labels/indice-de-reparabilite-10.152x90.svg"; + } # Initialize name and setting name if a language is requested @@ -1656,57 +1667,68 @@ sub compute_attributes ($product_ref, $target_lc, $target_cc, $options_ref) { # Nutritional quality - $attribute_ref = compute_attribute_nutriscore($product_ref, $target_lc, $target_cc); - add_attribute_to_group($product_ref, $target_lc, "nutritional_quality", $attribute_ref); - - foreach my $nutrient ("salt", "fat", "sugars", "saturated-fat") { - $attribute_ref = compute_attribute_nutrient_level($product_ref, $target_lc, "low", $nutrient); + if (defined $attribute_groups{"nutritional_quality"}) { + $attribute_ref = compute_attribute_nutriscore($product_ref, $target_lc, $target_cc); add_attribute_to_group($product_ref, $target_lc, "nutritional_quality", $attribute_ref); + + foreach my $nutrient ("salt", "fat", "sugars", "saturated-fat") { + $attribute_ref = compute_attribute_nutrient_level($product_ref, $target_lc, "low", $nutrient); + add_attribute_to_group($product_ref, $target_lc, "nutritional_quality", $attribute_ref); + } } # Allergens - foreach my $allergen_attribute_id (@{$attribute_groups{"allergens"}}) { - $attribute_ref = compute_attribute_allergen($product_ref, $target_lc, $allergen_attribute_id); - add_attribute_to_group($product_ref, $target_lc, "allergens", $attribute_ref); + if (defined $attribute_groups{"allergens"}) { + foreach my $allergen_attribute_id (@{$attribute_groups{"allergens"}}) { + $attribute_ref = compute_attribute_allergen($product_ref, $target_lc, $allergen_attribute_id); + add_attribute_to_group($product_ref, $target_lc, "allergens", $attribute_ref); + } } # Ingredients analysis - foreach my $analysis ("vegan", "vegetarian", "palm-oil-free") { - $attribute_ref = compute_attribute_ingredients_analysis($product_ref, $target_lc, $analysis); - add_attribute_to_group($product_ref, $target_lc, "ingredients_analysis", $attribute_ref); + if (defined $attribute_groups{"ingredients_analysis"}) { + foreach my $analysis ("vegan", "vegetarian", "palm-oil-free") { + $attribute_ref = compute_attribute_ingredients_analysis($product_ref, $target_lc, $analysis); + add_attribute_to_group($product_ref, $target_lc, "ingredients_analysis", $attribute_ref); + } } # Processing - $attribute_ref = compute_attribute_nova($product_ref, $target_lc); - add_attribute_to_group($product_ref, $target_lc, "processing", $attribute_ref); + if (defined $attribute_groups{"processing"}) { + $attribute_ref = compute_attribute_nova($product_ref, $target_lc); + add_attribute_to_group($product_ref, $target_lc, "processing", $attribute_ref); - $attribute_ref = compute_attribute_additives($product_ref, $target_lc); - add_attribute_to_group($product_ref, $target_lc, "processing", $attribute_ref); + $attribute_ref = compute_attribute_additives($product_ref, $target_lc); + add_attribute_to_group($product_ref, $target_lc, "processing", $attribute_ref); + } # Environment - if ( (not defined $options_ref) - or (not defined $options_ref->{skip_ecoscore}) - or (not $options_ref->{skip_ecoscore})) - { + if (feature_enabled("ecoscore")) { $attribute_ref = compute_attribute_ecoscore($product_ref, $target_lc, $target_cc); add_attribute_to_group($product_ref, $target_lc, "environment", $attribute_ref); } - if ( (not defined $options_ref) - or (not defined $options_ref->{skip_forest_footprint}) - or (not $options_ref->{skip_forest_footprint})) - { + if (feature_enabled("forest_footprint")) { $attribute_ref = compute_attribute_forest_footprint($product_ref, $target_lc); add_attribute_to_group($product_ref, $target_lc, "environment", $attribute_ref); } + if (defined $attributes{"repairability_index_france"}) { + $attribute_ref = compute_attribute_repairability_index_france($product_ref, $target_lc, $target_cc); + add_attribute_to_group($product_ref, $target_lc, "environment", $attribute_ref); + } + # Labels groups - foreach my $label_id ("en:organic", "en:fair-trade") { + if (defined $attributes{"labels_organic"}) { + $attribute_ref = compute_attribute_has_tag($product_ref, $target_lc, "labels", "en:organic"); + add_attribute_to_group($product_ref, $target_lc, "labels", $attribute_ref); + } - $attribute_ref = compute_attribute_has_tag($product_ref, $target_lc, "labels", $label_id); + if (defined $attributes{"labels_fair_trade"}) { + $attribute_ref = compute_attribute_has_tag($product_ref, $target_lc, "labels", "en:fair-trade"); add_attribute_to_group($product_ref, $target_lc, "labels", $attribute_ref); } @@ -1721,4 +1743,129 @@ sub compute_attributes ($product_ref, $target_lc, $target_cc, $options_ref) { return; } +=head2 compute_attribute_repairability_index_france ( $product_ref, $target_lc, $target_cc ) + +Compute the repairability index attribute for France. + +=head3 Arguments + +=head4 product reference $product_ref + +Loaded from the MongoDB database, Storable files, or the OFF API. + +=head4 language code $target_lc + +Returned attributes contain both data and strings intended to be displayed to users. + +=head4 country code $target_cc + +The repairability index is specific to France. + +=head3 Return value + +The return value is a reference to the resulting attribute data structure. + +=head4 % Match + +- 10x the repairability index value (from 0 to 10) +- 0% if the product does not have a repairability index value + +=cut + +sub compute_attribute_repairability_index_france ($product_ref, $target_lc, $target_cc) { + + $log->debug("compute repairability index attribute", + {code => $product_ref->{code}, ecoscore_data => $product_ref->{labels_tags}}) + if $log->is_debug(); + + my $attribute_id = "repairability_index_france"; + + my $attribute_ref = initialize_attribute($attribute_id, $target_lc); + + $attribute_ref->{status} = "unknown"; + + # Check if the product has a label indicating the repairability index + # with a repairability_index_france_value:en: property + + my ($value, $label_tag) + = get_inherited_property_from_tags("labels", $product_ref->{labels_tags}, + "repairability_index_france_value:en"); + if (defined $value) { + $attribute_ref->{status} = "known"; + my $value_dash = $value; + $value_dash =~ s/\./-/; + # Compute match based on the repairability index value (from 0 to 10) + $attribute_ref->{match} = $value * 10; + $attribute_ref->{icon_url} + = "$static_subdomain/images/lang/fr/labels/indice-de-reparabilite-$value_dash.152x90.svg"; + if ($target_lc ne "data") { + $attribute_ref->{title} = display_taxonomy_tag($target_lc, "labels", $label_tag); + my $value_description = "bad"; + if ($value >= 8) { + $value_description = "very_good"; + } + elsif ($value >= 6) { + $value_description = "good"; + } + elsif ($value >= 4) { + $value_description = "average"; + } + elsif ($value >= 2) { + $value_description = "bad"; + } + $attribute_ref->{description_short} + = lang_in_other_lc($target_lc, + "attribute_repairability_index_france_" . $value_description . "_description_short"); + + } + } + # Check if the product is in an applicable category + # (smartphones, laptops, electric lawn mowers, dishwashers, vacuum cleaners and high-pressure cleaners) + # https://www.ecologie.gouv.fr/politiques-publiques/indice-reparabilite#lobjectif-de-lindice-0 + elsif ( + not( + (defined $product_ref->{categories_tags}) and ( + scalar( + grep { + $_ + =~ /en:(smartphones|laptops|electric-lawn-mowers|dishwashers|vacuum-cleaners|high-pressure-cleaners)/ + } @{$product_ref->{categories_tags}} + ) + ) + ) + ) + { + $attribute_ref->{icon_url} + = "$static_subdomain/images/lang/fr/labels/indice-de-reparabilite-non-applicable.152x90.svg"; + if ($target_lc ne "data") { + $attribute_ref->{title} + = lang_in_other_lc($target_lc, "attribute_repairability_index_france_not_applicable_title"); + $attribute_ref->{description_short} + = lang_in_other_lc($target_lc, "attribute_repairability_index_france_not_applicable_description_short"); + $attribute_ref->{description} = f_lang_in_lc( + $target_lc, + "f_attribute_repairability_index_france_not_applicable_description", + { + categories => join(',', + map {display_taxonomy_tag($target_lc, "categories", $_)} "en:smartphones", + "en:laptops", "en:electric-lawn-mowers", "en:dishwashers", + "en:vacuum-cleaners", "en:high-pressure-cleaners") + } + ); + } + } + else { + $attribute_ref->{icon_url} + = "$static_subdomain/images/lang/fr/labels/indice-de-reparabilite-inconnu.152x90.svg"; + if ($target_lc ne "data") { + $attribute_ref->{title} + = lang_in_other_lc($target_lc, "attribute_repairability_index_france_unknown_title"); + $attribute_ref->{description_short} + = lang_in_other_lc($target_lc, "attribute_repairability_index_france_unknown_description_short"); + } + } + + return $attribute_ref; +} + 1; diff --git a/lib/ProductOpener/Config_obf.pm b/lib/ProductOpener/Config_obf.pm index 929b3fd8b8d57..86addf91a26c0 100644 --- a/lib/ProductOpener/Config_obf.pm +++ b/lib/ProductOpener/Config_obf.pm @@ -183,6 +183,19 @@ $flavor = 'obf'; ios_app_link => "https://apps.apple.com/app/open-beauty-facts/id1122926380?utm_source=obf&utf_medium=web", facebook_page_url => "https://www.facebook.com/openbeautyfacts?utm_source=obf&utf_medium=web", twitter_account => "OpenBeautyFacts", + # favicon HTML and images generated with https://realfavicongenerator.net/ using the SVG icon + favicons => < + + + + + + + + +HTML + , ); $options{export_limit} = 10000; @@ -484,6 +497,21 @@ HTML last_image_t ); +# Used to generate the list of possible product attributes, which is +# used to display the possible choices for user preferences +$options{attribute_groups} + = [["ingredients_analysis", ["vegan", "palm_oil_free",]], ["labels", ["labels_organic", "labels_fair_trade"]],]; + +# default preferences for attributes +$options{attribute_default_preferences} = { + "labels_organic" => "important", + "labels_fair_trade" => "important", +}; + +use JSON::MaybeXS; +$options{attribute_default_preferences_json} + = JSON->new->utf8->canonical->encode($options{attribute_default_preferences}); + # for ingredients OCR, we use tesseract-ocr # on debian, dictionaries are in /usr/share/tesseract-ocr/tessdata # %tesseract_ocr_available_languages provides mapping between OFF 2 letter language codes diff --git a/lib/ProductOpener/Config_off.pm b/lib/ProductOpener/Config_off.pm index f0ba69f6f433c..b6ee9c7f01037 100644 --- a/lib/ProductOpener/Config_off.pm +++ b/lib/ProductOpener/Config_off.pm @@ -204,6 +204,19 @@ $flavor = 'off'; facebook_page_url_fr => "https://www.facebook.com/OpenFoodFacts.fr", twitter_account => "OpenFoodFacts", twitter_account_fr => "OpenFoodFactsFr", + # favicon HTML and images generated with https://realfavicongenerator.net/ using the SVG icon + favicons => < + + + + + + + + +HTML + , ); $options{export_limit} = 10000; @@ -545,22 +558,6 @@ $options{manifest} = $manifest; $options{display_random_sample_of_products_after_edits} = 0; # from MongoDB 3.2 onward -$options{favicons} = < - - - - - - - - - - - -HTML - ; - $options{opensearch_image} = <https://static.$server_domain/images/favicon/favicon.ico XML @@ -993,6 +990,10 @@ $options{attribute_default_preferences} = { "ecoscore" => "important", }; +use JSON::MaybeXS; +$options{attribute_default_preferences_json} + = JSON->new->utf8->canonical->encode($options{attribute_default_preferences}); + # Used to generate the sample import file for the producers platform # possible values: mandatory, recommended, optional. # when not specified, fields are considered optional diff --git a/lib/ProductOpener/Config_opf.pm b/lib/ProductOpener/Config_opf.pm index 54c049c97078e..8ae929e532a07 100644 --- a/lib/ProductOpener/Config_opf.pm +++ b/lib/ProductOpener/Config_opf.pm @@ -174,13 +174,26 @@ $flavor = "opf"; %options = ( site_name => "Open Products Facts", - product_type => "products", + product_type => "product", og_image_url => "https://world.openproductsfacts.org/images/misc/openproductsfacts-logo-en.png", #android_apk_app_link => "https://world.openbeautyfacts.org/images/apps/obf.apk?utm_source=opf&utf_medium=web", #android_app_link => "https://play.google.com/store/apps/details?id=org.openbeautyfacts.scanner&utm_source=opf&utf_medium=web", #ios_app_link => "https://apps.apple.com/app/open-beauty-facts/id1122926380?utm_source=opf&utf_medium=web", #facebook_page_url => "https://www.facebook.com/openbeautyfacts?&utm_source=opf&utf_medium=web", #twitter_account => "OpenBeautyFacts", + # favicon HTML and images generated with https://realfavicongenerator.net/ using the SVG icon + favicons => < + + + + + + + + +HTML + , ); $options{export_limit} = 10000; @@ -305,20 +318,17 @@ HTML @taxonomy_fields = qw( units languages states countries - allergens origins additives_classes ingredients + origins packaging_shapes packaging_materials packaging_recycling packaging - labels food_groups categories - ingredients_processing - additives vitamins minerals amino_acids nucleotides other_nutritional_substances traces - ingredients_analysis - nutrients nutrient_levels misc nova_groups + labels categories + misc periods_after_opening data_quality data_quality_bugs data_quality_info data_quality_warnings data_quality_errors data_quality_warnings_producers data_quality_errors_producers improvements ); # tag types (=facets) that should be indexed by web crawlers, all other tag types are not indexable -@index_tag_types = qw(brands categories labels additives nova_groups ecoscore nutrition_grades products); +@index_tag_types = qw(brands categories labels products); # fields in product edit form, above ingredients and nutrition facts @@ -481,6 +491,22 @@ HTML last_image_t ); +# Used to generate the list of possible product attributes, which is +# used to display the possible choices for user preferences +$options{attribute_groups} + = [["labels", ["labels_organic", "labels_fair_trade"]], ["environment", ["repairability_index_france",]],]; + +# default preferences for attributes +$options{attribute_default_preferences} = { + "labels_organic" => "important", + "labels_fair_trade" => "important", + "repairability_index_france" => "important", +}; + +use JSON::MaybeXS; +$options{attribute_default_preferences_json} + = JSON->new->utf8->canonical->encode($options{attribute_default_preferences}); + # for ingredients OCR, we use tesseract-ocr # on debian, dictionaries are in /usr/share/tesseract-ocr/tessdata # %tesseract_ocr_available_languages provides mapping between OFF 2 letter language codes diff --git a/lib/ProductOpener/Config_opff.pm b/lib/ProductOpener/Config_opff.pm index 310435fb01bf1..02554b1b19f63 100644 --- a/lib/ProductOpener/Config_opff.pm +++ b/lib/ProductOpener/Config_opff.pm @@ -181,6 +181,21 @@ $flavor = "opff"; #ios_app_link => "https://apps.apple.com/app/open-beauty-facts/id1122926380?utm_source=opff&utf_medium=web", #facebook_page_url => "https://www.facebook.com/openbeautyfacts?utm_source=opff&utf_medium=web", #twitter_account => "OpenBeautyFacts", + default_preferences => + '{ "nova" : "important", "labels_organic" : "important", "labels_fair_trade" : "important" }', + # favicon HTML and images generated with https://realfavicongenerator.net/ using the SVG icon + favicons => < + + + + + + + + +HTML + , ); $options{export_limit} = 10000; @@ -510,6 +525,20 @@ XML last_image_t ); +# Used to generate the list of possible product attributes, which is +# used to display the possible choices for user preferences +$options{attribute_groups} = [["labels", ["labels_organic", "labels_fair_trade"]],]; + +# default preferences for attributes +$options{attribute_default_preferences} = { + "labels_organic" => "important", + "labels_fair_trade" => "important", +}; + +use JSON::MaybeXS; +$options{attribute_default_preferences_json} + = JSON->new->utf8->canonical->encode($options{attribute_default_preferences}); + # for ingredients OCR, we use tesseract-ocr # on debian, dictionaries are in /usr/share/tesseract-ocr/tessdata # %tesseract_ocr_available_languages provides mapping between OFF 2 letter language codes diff --git a/lib/ProductOpener/Display.pm b/lib/ProductOpener/Display.pm index f763bd4aab648..5c728c65c9dba 100644 --- a/lib/ProductOpener/Display.pm +++ b/lib/ProductOpener/Display.pm @@ -961,11 +961,9 @@ CSS $knowledge_panels_options_ref = {}; if (not feature_enabled("ecoscore")) { - $attributes_options_ref->{skip_ecoscore} = 1; $knowledge_panels_options_ref->{skip_ecoscore} = 1; } if (not feature_enabled("forest_footprint")) { - $attributes_options_ref->{skip_forest_footprint} = 1; $knowledge_panels_options_ref->{skip_forest_footprint} = 1; } @@ -1340,6 +1338,10 @@ sub display_text ($request_ref) { } my $file = "$BASE_DIRS{LANG}/$text_lc/texts/" . $texts{$textid}{$text_lc}; + # Check if we have a flavor specific version + if (-e "$BASE_DIRS{LANG}/$flavor/$text_lc/texts/" . $texts{$textid}{$text_lc}) { + $file = "$BASE_DIRS{LANG}/$flavor/$text_lc/texts/" . $texts{$textid}{$text_lc}; + } display_text_content($request_ref, $textid, $text_lc, $file); return; @@ -4547,6 +4549,7 @@ sub display_search_results ($request_ref) { $request_ref->{scripts} .= < var page_type = "products"; +var default_preferences = $options{attribute_default_preferences_json}; var preferences_text = "$preferences_text"; var contributor_prefs = $contributor_prefs_json; var products = []; @@ -5705,6 +5708,7 @@ sub search_and_display_products ($request_ref, $query_ref, $sort_by, $limit, $pa $request_ref->{scripts} .= < var page_type = "products"; +var default_preferences = $options{attribute_default_preferences_json}; var preferences_text = "$preferences_text"; var contributor_prefs = $contributor_prefs_json; var products = $products_json; @@ -7956,6 +7960,10 @@ JS = display_knowledge_panel($product_ref, $product_ref->{"knowledge_panels_" . $lc}, "environment_card"); $template_data_ref->{health_card_panel} = display_knowledge_panel($product_ref, $product_ref->{"knowledge_panels_" . $lc}, "health_card"); + if ($product_ref->{"knowledge_panels_" . $lc}{"secondhand_card"}) { + $template_data_ref->{secondhand_card_panel} + = display_knowledge_panel($product_ref, $product_ref->{"knowledge_panels_" . $lc}, "secondhand_card"); + } $template_data_ref->{report_problem_card_panel} = display_knowledge_panel($product_ref, $product_ref->{"knowledge_panels_" . $lc}, "report_problem_card"); if ($product_ref->{"knowledge_panels_" . $lc}{"contribution_card"}) { @@ -8569,6 +8577,7 @@ HTML $request_ref->{scripts} .= < var page_type = "product"; +var default_preferences = $options{attribute_default_preferences_json}; var preferences_text = "$preferences_text"; var product = $product_attribute_groups_json; diff --git a/lib/ProductOpener/Index.pm b/lib/ProductOpener/Index.pm index e09b2d3db666b..a85c88d7f85a3 100644 --- a/lib/ProductOpener/Index.pm +++ b/lib/ProductOpener/Index.pm @@ -80,37 +80,42 @@ if (not -e $lang_dir) { ) if $log->is_warn(); } -if (opendir DH2, $lang_dir) { - - $log->info("Reading texts from $lang_dir") if $log->is_info(); - - foreach my $langid (readdir(DH2)) { - next if $langid eq '.'; - next if $langid eq '..'; - #$log->trace("reading texts", { lang => $langid }) if $log->is_trace(); - next if ((length($langid) ne 2) and not($langid eq 'other')); - - if (-e "$lang_dir/$langid/texts") { - opendir DH, "$lang_dir/$langid/texts" or die "Couldn't open $lang_dir/$langid/texts: $!"; - foreach my $textid (readdir(DH)) { - next if $textid eq '.'; - next if $textid eq '..'; - my $file = $textid; - $textid =~ s/(\.foundation)?(\.$langid)?\.html//; - defined $texts{$textid} or $texts{$textid} = {}; - # prefer the .foundation version - if ((not defined $texts{$textid}{$langid}) or (length($file) > length($texts{$textid}{$langid}))) { - $texts{$textid}{$langid} = $file; +# Check both $lang_dir + flavor specific directory + +foreach my $dir ($lang_dir, "$lang_dir/$flavor") { + + if (opendir DH2, $dir) { + + $log->info("Reading texts from $lang_dir") if $log->is_info(); + + foreach my $langid (readdir(DH2)) { + next if $langid eq '.'; + next if $langid eq '..'; + #$log->trace("reading texts", { lang => $langid }) if $log->is_trace(); + next if ((length($langid) ne 2) and not($langid eq 'other')); + + if (-e "$dir/$langid/texts") { + opendir DH, "$dir/$langid/texts" or die "Couldn't open $dir/$langid/texts: $!"; + foreach my $textid (readdir(DH)) { + next if $textid eq '.'; + next if $textid eq '..'; + my $file = $textid; + $textid =~ s/(\.foundation)?(\.$langid)?\.html//; + defined $texts{$textid} or $texts{$textid} = {}; + # prefer the .foundation version + if ((not defined $texts{$textid}{$langid}) or (length($file) > length($texts{$textid}{$langid}))) { + $texts{$textid}{$langid} = $file; + } + + #$log->trace("text loaded", { langid => $langid, textid => $textid }) if $log->is_trace(); } - - #$log->trace("text loaded", { langid => $langid, textid => $textid }) if $log->is_trace(); + closedir(DH); } - closedir(DH); } + closedir(DH2); } - closedir(DH2); } -else { +if (scalar keys %texts == 0) { $log->error("Texts could not be loaded.") if $log->is_error(); die("Texts could not be loaded from $BASE_DIRS{LANG} or $BASE_DIRS{LANG}-default"); } diff --git a/lib/ProductOpener/KnowledgePanels.pm b/lib/ProductOpener/KnowledgePanels.pm index 47abeb1557d88..5245cbbef3b9b 100644 --- a/lib/ProductOpener/KnowledgePanels.pm +++ b/lib/ProductOpener/KnowledgePanels.pm @@ -241,6 +241,12 @@ sub create_knowledge_panels ($product_ref, $target_lc, $target_cc, $options_ref, $has_contribution_card = create_contribution_card_panel($product_ref, $target_lc, $target_cc, $options_ref); } + my $has_secondhand_card; + if ($panel_is_requested->('secondhand_card')) { + $has_secondhand_card + = create_secondhand_card_panel($product_ref, $target_lc, $target_cc, $options_ref, $request_ref); + } + # Create the root panel that contains the panels we want to show directly on the product page create_panel_from_json_template( "root", @@ -250,6 +256,7 @@ sub create_knowledge_panels ($product_ref, $target_lc, $target_cc, $options_ref, has_report_problem_card => $has_report_problem_card, has_contribution_card => $has_contribution_card, has_environment_card => $has_environment_card, + has_secondhand_card => $has_secondhand_card, }, $product_ref, $target_lc, @@ -632,7 +639,8 @@ sub create_ecoscore_panel ($product_ref, $target_lc, $target_cc, $options_ref, $ # } # } - create_panel_from_json_template("carbon_footprint", "api/knowledge-panels/environment/carbon_footprint.tt.json", + create_panel_from_json_template("carbon_footprint", + "api/knowledge-panels/environment/carbon_footprint_food.tt.json", $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); # Add panels for the different bonuses and maluses @@ -765,6 +773,11 @@ sub create_environment_card_panel ($product_ref, $target_lc, $target_cc, $option } } + # Create panel for carbon footprint (non-food products, for food products, it is added by create_ecoscore_panel) + if ($options{product_type} ne "food") { + create_carbon_footprint_panel($product_ref, $target_lc, $target_cc, $options_ref); + } + # Create panel for packaging components, and packaging materials create_panel_from_json_template("packaging_recycling", "api/knowledge-panels/environment/packaging_recycling.tt.json", @@ -780,22 +793,111 @@ sub create_environment_card_panel ($product_ref, $target_lc, $target_cc, $option create_manufacturing_place_panel($product_ref, $target_lc, $target_cc, $options_ref); # Origins of ingredients for the environment card, for food, pet food and beauty products - if ( ($options{product_type} eq "food") - or ($options{product_type} eq "pet_food") - or ($options{product_type} eq "beauty")) - { + if (feature_enabled("ingredients")) { create_panel_from_json_template("origins_of_ingredients", "api/knowledge-panels/environment/origins_of_ingredients.tt.json", $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); } # Create the environment_card panel - $panel_data_ref->{packaging_image} = data_to_display_image($product_ref, "packaging", $target_lc), - create_panel_from_json_template("environment_card", "api/knowledge-panels/environment/environment_card.tt.json", + $panel_data_ref->{packaging_image} = data_to_display_image($product_ref, "packaging", $target_lc); + create_panel_from_json_template("environment_card", "api/knowledge-panels/environment/environment_card.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + return 1; +} + +=head2 create_secondhand_card_panel ( $product_ref, $target_lc, $target_cc, $options_ref ) + +Creates a knowledge panel card that contains all knowledge panels related to the circular economy: +- sharing, buying, selling etc. + +Created for products in specific categories, for users in specific countries. + +=head3 Arguments + +=head4 product reference $product_ref + +Loaded from the MongoDB database, Storable files, or the OFF API. + +=head4 language code $target_lc + +Returned attributes contain both data and strings intended to be displayed to users. +This parameter sets the desired language for the user facing strings. + +=head4 country code $target_cc + +Used to select secondhand options (e.g. classified ads sites) that are relevant for the user. + +=cut + +sub create_secondhand_card_panel ($product_ref, $target_lc, $target_cc, $options_ref, $request_ref) { + + $log->debug("create secondhand card panel", {code => $product_ref->{code}}) if $log->is_debug(); + + my $panel_data_ref = {}; + + # Only available for the product_type "product" + if ($options{product_type} ne "product") { + return 0; + } + + # Add the name of the most specific category (last in categories_hierarchy) to the panel data + my $category_id = $product_ref->{categories_hierarchy}[-1]; + $panel_data_ref->{category_name} = display_taxonomy_tag_name($target_lc, "categories", $category_id); + + # Create paneld for donations + + create_panel_from_json_template("donated_products_fr_geev", + "api/knowledge-panels/secondhand/donated_products_fr_geev.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + + create_panel_from_json_template("donated_products", "api/knowledge-panels/secondhand/donated_products.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + + # Created panels for buying used products + create_panel_from_json_template("used_products_fr_backmarket", + "api/knowledge-panels/secondhand/used_products_fr_backmarket.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + + create_panel_from_json_template("used_products", "api/knowledge-panels/secondhand/used_products.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + + # Create the secondhand_card panel + + create_panel_from_json_template("secondhand_card", "api/knowledge-panels/secondhand/secondhand_card.tt.json", $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + return 1; } +sub create_carbon_footprint_panel($product_ref, $target_lc, $target_cc, $options_ref) { + + # Find the first category that has a carbon_impact_fr_impactco2:en: property + my ($value, $category_id) + = get_inherited_property_from_categories_tags($product_ref, "carbon_impact_fr_impactco2:en"); + + $log->debug("create carbon footprint panel", + {code => $product_ref->{code}, category_id => $category_id, value => $value}) + if $log->is_debug(); + + if (defined $value) { + + my $panel_data_ref = { + category_id => $category_id, + category_name => display_taxonomy_tag_name($target_lc, "categories", $category_id), + co2_kg_per_unit => $value, + unit_name => get_property_with_fallbacks("categories", $category_id, "unit_name:$target_lc"), + link => get_property("categories", $category_id, "carbon_impact_fr_impactco2_link:en"), + }; + + create_panel_from_json_template("carbon_footprint", + "api/knowledge-panels/environment/carbon_footprint_product.tt.json", + $panel_data_ref, $product_ref, $target_lc, $target_cc, $options_ref); + } + + return; +} + =head2 create_manufacturing_place_panel ( $product_ref, $target_lc, $target_cc, $options_ref ) Creates a knowledge panel when we know the location of the manufacturing place, diff --git a/lib/ProductOpener/Paths.pm b/lib/ProductOpener/Paths.pm index 8662de0fb6a82..dc1b4fd0da056 100644 --- a/lib/ProductOpener/Paths.pm +++ b/lib/ProductOpener/Paths.pm @@ -42,8 +42,8 @@ BEGIN { @EXPORT_OK = qw( %BASE_DIRS - &get_path_for_taxonomy - &get_file_for_taxonomy + &get_path_for_taxonomy_file + &get_files_for_taxonomy &base_paths &base_paths_loading_script &check_missing_dirs @@ -334,7 +334,7 @@ sub _source_dir() { return $src_root; } -=head2 get_file_for_taxonomy( $tagtype ) +=head2 get_files_for_taxonomy( $tagtype ) Taxonomy .txt source files are stored in the /taxonomies directory. @@ -349,15 +349,18 @@ e.g. OFF ingredients are in /taxonomies/food/ingredients.txt and OBF ingredients =cut -sub get_file_for_taxonomy ($tagtype, $product_type) { +sub get_files_for_taxonomy ($tagtype, $product_type) { - my $file = $tagtype . '.txt'; - # If the flavor has a specific product type, first check if we have a source file for this product type + my @files = (); + # Check if there is a common taxonomy file for this tag type + if (-e "$BASE_DIRS{TAXONOMIES_SRC}/$tagtype.txt") { + push @files, "$tagtype.txt"; + } + # Check if there is product type specific taxonomy file for this tag type if ((defined $product_type) and (-e "$BASE_DIRS{TAXONOMIES_SRC}/$product_type/$tagtype.txt")) { - $file = "$product_type/$tagtype.txt"; + push @files, "$product_type/$tagtype.txt"; } - - return $file; + return @files; } =head2 get_path_for_taxonomy( $tagtype, $product_type ) @@ -366,9 +369,8 @@ full path for taxonomy file =cut -sub get_path_for_taxonomy($tagtype, $product_type) { +sub get_path_for_taxonomy_file($source_file) { # The source file can be prefixed by the product type - my $source_file = get_file_for_taxonomy($tagtype, $product_type); return "$BASE_DIRS{TAXONOMIES_SRC}/$source_file"; } diff --git a/lib/ProductOpener/Products.pm b/lib/ProductOpener/Products.pm index 8af458c933e0c..1eefc59a31789 100644 --- a/lib/ProductOpener/Products.pm +++ b/lib/ProductOpener/Products.pm @@ -772,6 +772,7 @@ sub init_product ($userid, $orgid, $code, $countryid) { created_t => time(), creator => $creator, rev => 0, + product_type => $options{product_type}, }; if (defined $server) { @@ -889,7 +890,6 @@ sub retrieve_product ($product_id) { my $product_ref = retrieve($full_product_path); - # If the product is on another server, set the server field so that it will be saved in the other server if we save it my $server = server_for_product_id($product_id); if (not defined $product_ref) { @@ -898,10 +898,9 @@ sub retrieve_product ($product_id) { if $log->is_debug(); } else { - if (defined $server) { - $product_ref->{server} = $server; + if ($product_ref->{deleted}) { $log->debug( - "retrieve_product - product on another server", + "retrieve_product - deleted product", { product_id => $product_id, product_data_root => $product_data_root, @@ -909,11 +908,15 @@ sub retrieve_product ($product_id) { server => $server } ) if $log->is_debug(); + return; } - if ($product_ref->{deleted}) { + # If the product is on another server, set the server field so that it will be saved in the other server if we save it + + if (defined $server) { + $product_ref->{server} = $server; $log->debug( - "retrieve_product - deleted product", + "retrieve_product - product on another server", { product_id => $product_id, product_data_root => $product_data_root, @@ -921,7 +924,10 @@ sub retrieve_product ($product_id) { server => $server } ) if $log->is_debug(); - return; + } + else { + # If the product was moved previously, it may have a server field, remove it + delete $product_ref->{server}; } } @@ -935,12 +941,6 @@ sub retrieve_product_or_deleted_product ($product_id, $deleted_ok = 1) { my $product_ref = retrieve("$product_data_root/products/$path/product.sto"); - # If the product is on another server, set the server field so that it will be saved in the other server if we save it - my $server = server_for_product_id($product_id); - if ((defined $product_ref) and (defined $server)) { - $product_ref->{server} = $server; - } - if ( (defined $product_ref) and ($product_ref->{deleted}) and (not $deleted_ok)) @@ -948,6 +948,18 @@ sub retrieve_product_or_deleted_product ($product_id, $deleted_ok = 1) { return; } + if (defined $product_ref) { + # If the product is on another server, set the server field so that it will be saved in the other server if we save it + my $server = server_for_product_id($product_id); + if (defined $server) { + $product_ref->{server} = $server; + } + else { + # If the product was moved previously, it may have a server field, remove it + delete $product_ref->{server}; + } + } + return $product_ref; } @@ -962,14 +974,21 @@ sub retrieve_product_rev ($product_id, $rev) { my $product_ref = retrieve("$product_data_root/products/$path/$rev.sto"); - # If the product is on another server, set the server field so that it will be saved in the other server if we save it - my $server = server_for_product_id($product_id); - if ((defined $product_ref) and (defined $server)) { - $product_ref->{server} = $server; - } + if (defined $product_ref) { - if ((defined $product_ref) and ($product_ref->{deleted})) { - return; + if ($product_ref->{deleted}) { + return; + } + + # If the product is on another server, set the server field so that it will be saved in the other server if we save it + my $server = server_for_product_id($product_id); + if (defined $server) { + $product_ref->{server} = $server; + } + else { + # If the product was moved previously, it may have a server field, remove it + delete $product_ref->{server}; + } } return $product_ref; diff --git a/lib/ProductOpener/ProductsFeatures.pm b/lib/ProductOpener/ProductsFeatures.pm index 4ef50234aa315..48c1eed92f3d8 100644 --- a/lib/ProductOpener/ProductsFeatures.pm +++ b/lib/ProductOpener/ProductsFeatures.pm @@ -74,13 +74,15 @@ my %product_type_features = ( additives => 1, nova => 1, nutrition => 1, + user_preferences => 1, }, beauty => { health_card => 1, ingredients => 1, + user_preferences => 1, }, - products => { - + product => { + user_preferences => 1, }, ); @@ -107,7 +109,13 @@ Currently not used, may be used later to determine features based on product fie =cut sub feature_enabled($feature, $product_ref = undef) { - my $enabled = deep_get(\%product_type_features, $options{product_type}, $feature); + # If we have a product reference, and the product type is set, use it + # otherwise use the product type of the site instance (e.g. "Open Food Facts" -> "food") + my $product_type + = ((defined $product_ref) and (defined $product_ref->{product_type})) + ? $product_ref->{product_type} + : $options{product_type}; + my $enabled = deep_get(\%product_type_features, $product_type, $feature); $log->debug("feature_enabled", {feature => $feature, product_type => $options{product_type}, enabled => $enabled}) if $log->is_debug(); return $enabled; diff --git a/lib/ProductOpener/Tags.pm b/lib/ProductOpener/Tags.pm index 92d329c05e6cf..de77b18376f1e 100644 --- a/lib/ProductOpener/Tags.pm +++ b/lib/ProductOpener/Tags.pm @@ -176,7 +176,7 @@ use vars @EXPORT_OK; use ProductOpener::Store qw/:all/; use ProductOpener::Config qw/:all/; -use ProductOpener::Paths qw/%BASE_DIRS ensure_dir_created_or_die get_file_for_taxonomy get_path_for_taxonomy/; +use ProductOpener::Paths qw/%BASE_DIRS ensure_dir_created_or_die get_files_for_taxonomy get_path_for_taxonomy_file/; use ProductOpener::Lang qw/$lc %Lang %tag_type_singular lang/; use ProductOpener::Text qw/normalize_percentages regexp_escape/; use ProductOpener::PackagerCodes qw/localize_packager_code normalize_packager_codes/; @@ -1072,6 +1072,7 @@ sub get_lc_tagid ($synonyms_ref, $lc, $tagtype, $tag, $warning) { sub get_file_from_cache ($source, $target) { my $cache_root = "$BASE_DIRS{CACHE_BUILD}/taxonomies"; + (-e $cache_root) or mkdir($cache_root, 0755); my $local_cache_source = "$cache_root/$source"; # first, try to get it localy @@ -1113,7 +1114,7 @@ sub get_from_cache ($tagtype, @files) { foreach my $source_file (@files) { # The source file can be prefixed by the product type - my $source_path = get_path_for_taxonomy($source_file, $options{product_type}); + my $source_path = get_path_for_taxonomy_file($source_file); open(my $IN, "<", $source_path) or die("Cannot open $source_path (tagtype: $tagtype - product_type: $options{product_type}): $!\n"); @@ -1238,16 +1239,20 @@ sub build_tags_taxonomy ($tagtype, $publish) { my $result_dir = "$BASE_DIRS{CACHE_BUILD}/taxonomies-result/"; ensure_dir_created_or_die("$result_dir"); - my @files = ($tagtype); + # Some taxonomy tag types include other tag types (e.g. origins includes countries) + my @tagtypes = ($tagtype); # For the origins taxonomy, include the countries taxonomy if ($tagtype eq "origins") { - @files = ("countries", "origins"); + @tagtypes = ("countries", "origins"); } # For the Open Food Facts ingredients taxonomy, concatenate additives, minerals, vitamins, nucleotides and other nutritional substances taxonomies - elsif (($tagtype eq "ingredients") and (defined $options{product_type}) and ($options{product_type} eq "food")) { - @files = ( + elsif ( ($tagtype eq "ingredients") + and (defined $options{product_type}) + and (($options{product_type} eq "food") or ($options{product_type} eq "petfood"))) + { + @tagtypes = ( "additives_classes", "additives", "minerals", "vitamins", "nucleotides", "other_nutritional_substances", "ingredients" ); @@ -1255,14 +1260,27 @@ sub build_tags_taxonomy ($tagtype, $publish) { # Packaging elsif (($tagtype eq "packaging")) { - @files = ("packaging_materials", "packaging_shapes", "packaging_recycling", "preservation"); + @tagtypes = ("packaging_materials", "packaging_shapes", "packaging_recycling", "preservation"); } # Traces - just a copy of allergens elsif ($tagtype eq "traces") { - @files = ("allergens"); + @tagtypes = ("allergens"); } + # List the individual taxonomy source files for all included tag types + # Each tag type can have a common and/or a product type specific source file. + + my @files = (); + foreach my $tagtype (@tagtypes) { + my @tagtype_files = get_files_for_taxonomy($tagtype, $options{product_type}); + if (scalar @tagtype_files == 0) { + die("No taxonomy file(s) found for $tagtype\n"); + } + push @files, @tagtype_files; + } + + # Check if we already have a cached version of the taxonomy my $cache_prefix = get_from_cache($tagtype, @files); if (!$cache_prefix) { return; @@ -1271,20 +1289,22 @@ sub build_tags_taxonomy ($tagtype, $publish) { print("building taxonomy for $tagtype - publish: $publish\n"); # Concatenate taxonomy files if needed - my $file = get_file_for_taxonomy($tagtype, $options{product_type}); - my $file_path = get_path_for_taxonomy($tagtype, $options{product_type}); - if ((scalar @files) > 1) { - $file = "$tagtype.all.txt"; - $file_path = "$result_dir/$file"; + my $file_path; + if ((scalar @files) == 1) { + # Only 1 file + $file_path = get_path_for_taxonomy_file($files[0]); + } + else { + # Multiple files + $file_path = "$result_dir/$tagtype.all.txt"; open(my $OUT, ">:encoding(UTF-8)", $file_path) or die("Cannot write $file_path : $!\n"); - foreach my $taxonomy (@files) { - my $taxonomy_file = get_file_for_taxonomy($taxonomy, $options{product_type}); - my $taxonomy_path = get_path_for_taxonomy($taxonomy, $options{product_type}); + foreach my $taxonomy_file (@files) { + my $taxonomy_path = get_path_for_taxonomy_file($taxonomy_file); open(my $IN, "<:encoding(UTF-8)", $taxonomy_path) - or die("Missing $taxonomy_path\n"); + or die("Cannot open $taxonomy_path: $!\n"); print $OUT "# $taxonomy_file\n\n"; @@ -3089,64 +3109,10 @@ sub get_taxonomy_tag_and_link_for_lang ($target_lc, $tagtype, $tagid) { my $taxonomy = $taxonomy_fields{$tagtype}; - my $tag_lc; - - if ($tagid =~ /^(\w\w):/) { - $tag_lc = $1; - } - - my $display = ''; - my $display_lc = "en"; # Default to English - my $exists_in_taxonomy = 0; - - if ( (defined $translations_to{$taxonomy}) - and (defined $translations_to{$taxonomy}{$tagid}) - and (defined $translations_to{$taxonomy}{$tagid}{$target_lc})) - { - # we have a translation for the target language - # print STDERR "display_taxonomy_tag - translation for the target language - translations_to{$taxonomy}{$tagid}{$target_lc} : $translations_to{$taxonomy}{$tagid}{$target_lc}\n"; - $display = $translations_to{$taxonomy}{$tagid}{$target_lc}; - $display_lc = $target_lc; - $exists_in_taxonomy = 1; - } - else { - # use tag language - if ( (defined $translations_to{$taxonomy}) - and (defined $translations_to{$taxonomy}{$tagid}) - and (defined $tag_lc) - and (defined $translations_to{$taxonomy}{$tagid}{$tag_lc})) - { - # we have a translation for the tag language - # print STDERR "display_taxonomy_tag - translation for the tag language - translations_to{$taxonomy}{$tagid}{$tag_lc} : $translations_to{$taxonomy}{$tagid}{$tag_lc}\n"; - - $display = "$tag_lc:" . $translations_to{$taxonomy}{$tagid}{$tag_lc}; - - $exists_in_taxonomy = 1; - } - else { - $display = $tagid; - if (defined $tag_lc) { - $display_lc = $tag_lc; - } - - if ($target_lc eq $tag_lc) { - $display =~ s/^(\w\w)://; - } - # print STDERR "display_taxonomy_tag - no translation available for $taxonomy $tagid in target language $lc or tag language $tag_lc - result: $display\n"; - } - } - - # for additives, add the first synonym - if ($taxonomy =~ /^additives(|_prev|_next|_debug)$/) { - $tagid =~ s/.*://; - if ( (defined $synonyms_for{$taxonomy}{$target_lc}) - and (defined $synonyms_for{$taxonomy}{$target_lc}{$tagid}) - and (defined $synonyms_for{$taxonomy}{$target_lc}{$tagid}[1])) - { - $display .= " - " . ucfirst($synonyms_for{$taxonomy}{$target_lc}{$tagid}[1]); - } - } + my $exists_in_taxonomy = exists_taxonomy_tag($tagtype, $tagid) || 0; + my $display = display_taxonomy_tag($target_lc, $tagtype, $tagid); + my $display_lc = $target_lc; my $display_lc_prefix = ""; my $display_tag = $display; @@ -4606,6 +4572,7 @@ sub init_tags_texts { return if (%tags_texts); $log->info("loading tags texts") if $log->is_info(); + if (opendir DH2, $lang_dir) { foreach my $langid (readdir(DH2)) { next if $langid eq '.'; diff --git a/po/common/common.pot b/po/common/common.pot index da7183b0d6396..217c0a1c1cfb7 100644 --- a/po/common/common.pot +++ b/po/common/common.pot @@ -5005,21 +5005,21 @@ msgctxt "ecoscore_information" msgid "Information about the Eco-score" msgstr "Information about the Eco-score" -msgctxt "preferences_edit_your_food_preferences" -msgid "Edit your food preferences" -msgstr "Edit your food preferences" - -msgctxt "preferences_your_preferences" -msgid "Your food preferences" -msgstr "Your food preferences" - msgctxt "preferences_currently_selected_preferences" msgid "Currently selected preferences" msgstr "Currently selected preferences" msgctxt "preferences_locally_saved" -msgid "Your food preferences are kept in your browser and never sent to Open Food Facts or anyone else." -msgstr "Your food preferences are kept in your browser and never sent to Open Food Facts or anyone else." +msgid "Your preferences are kept in your browser and never sent to Open Food Facts or anyone else." +msgstr "Your preferences are kept in your browser and never sent to Open Food Facts or anyone else." + +msgctxt "preferences_edit_your_preferences" +msgid "Edit your preferences" +msgstr "Edit your preferences" + +msgctxt "preferences_your_preferences" +msgid "Your preferences" +msgstr "Your preferences" # used in phrases like "salt in unknown quantity" msgctxt "unknown_quantity" @@ -5850,8 +5850,21 @@ msgstr "Carbon footprint" # variable names between { } must not be translated msgctxt "f_carbon_footprint_per_100g_of_product" -msgid "{grams} g CO² per 100g of product" -msgstr "{grams} g CO² per 100g of product" +msgid "{grams} g CO₂e per 100g of product" +msgstr "{grams} g CO₂e per 100g of product" + +# variable names between { } must not be translated +msgctxt "f_carbon_footprint_per_unit" +msgid "{kilograms} kg CO₂e per unit" +msgstr "{kilograms} kg CO₂e per unit" + +msgctxt "average_for_the_category" +msgid "average for the category" +msgstr "average for the category" + +msgctxt "data_source_and_detailed_carbon_impact" +msgid "Data source and detailed carbon impact" +msgstr "Data source and detailed carbon impact" # variable names between { } must not be translated msgctxt "f_equal_to_driving_km_in_a_petrol_car" @@ -7119,3 +7132,77 @@ msgstr "Organization list" msgctxt "open_org" msgid "Open org" msgstr "Open org" + +msgctxt "secondhand" +msgid "Secondhand" +msgstr "Secondhand" + +msgctxt "donated_products_title" +msgid "Donations" +msgstr "Donations" + +msgctxt "donated_products_subtitle" +msgid "Give this product, or search for a similar donated product" +msgstr "Give this product, or search for a similar donated product" + +msgctxt "used_products_title" +msgid "Used products" +msgstr "Used products" + +msgctxt "used_products_subtitle" +msgid "Buy this product used, or search for a similar used product" +msgstr "Buy this product used, or search for a similar used product" + +msgctxt "attribute_repairability_index_france_name" +msgid "Repairability index" +msgstr "Repairability index" + +msgctxt "attribute_repairability_index_france_setting_name" +msgid "Good repairability" +msgstr "Good repairability" + +msgctxt "attribute_repairability_index_france_setting_note" +msgid "Mandatory rating in France for certain products since 2021" +msgstr "Mandatory rating in France for certain products since 2021" + +# keep %s, it will be replaced by the letter A, B, C, D or E +msgctxt "attribute_repairability_index_france_grade_title" +msgid "Repairability index %s" +msgstr "Repairability index %s" + +msgctxt "attribute_repairability_index_france_unknown_title" +msgid "Repairability index unknown" +msgstr "Repairability index unknown" + +msgctxt "attribute_repairability_index_france_not_applicable_title" +msgid "Repairability index not-applicable" +msgstr "Repairability index not-applicable" + +msgctxt "attribute_repairability_index_france_not_applicable_description_short" +msgid "Not-applicable for the category" +msgstr "Not-applicable for the category" + +# variable names between { } must not be translated +msgctxt "f_attribute_repairability_index_france_not_applicable_description" +msgid "Applicable only for categories: {categories}" +msgstr "Applicable only for categories: {categories}" + +msgctxt "attribute_repairability_index_france_very_good_description_short" +msgid "Very good repairability" +msgstr "Very good repairability" + +msgctxt "attribute_repairability_index_france_good_description_short" +msgid "Good repairability" +msgstr "Good repairability" + +msgctxt "attribute_repairability_index_france_average_description_short" +msgid "Average repairability" +msgstr "Average repairability" + +msgctxt "attribute_repairability_index_france_poor_description_short" +msgid "Poor repairability" +msgstr "Poor repairability" + +msgctxt "attribute_repairability_index_france_bad_description_short" +msgid "Bad repairability" +msgstr "Bad repairability" diff --git a/po/common/en.po b/po/common/en.po index ff904a0d64c4f..170b7486e5ab2 100644 --- a/po/common/en.po +++ b/po/common/en.po @@ -5029,21 +5029,21 @@ msgctxt "ecoscore_information" msgid "Information about the Eco-score" msgstr "Information about the Eco-score" -msgctxt "preferences_edit_your_food_preferences" -msgid "Edit your food preferences" -msgstr "Edit your food preferences" - -msgctxt "preferences_your_preferences" -msgid "Your food preferences" -msgstr "Your food preferences" - msgctxt "preferences_currently_selected_preferences" msgid "Currently selected preferences" msgstr "Currently selected preferences" msgctxt "preferences_locally_saved" -msgid "Your food preferences are kept in your browser and never sent to Open Food Facts or anyone else." -msgstr "Your food preferences are kept in your browser and never sent to Open Food Facts or anyone else." +msgid "Your preferences are kept in your browser and never sent to Open Food Facts or anyone else." +msgstr "Your preferences are kept in your browser and never sent to Open Food Facts or anyone else." + +msgctxt "preferences_edit_your_preferences" +msgid "Edit your preferences" +msgstr "Edit your preferences" + +msgctxt "preferences_your_preferences" +msgid "Your preferences" +msgstr "Your preferences" # used in phrases like "salt in unknown quantity" msgctxt "unknown_quantity" @@ -5874,8 +5874,21 @@ msgstr "Carbon footprint" # variable names between { } must not be translated msgctxt "f_carbon_footprint_per_100g_of_product" -msgid "{grams} g CO² per 100g of product" -msgstr "{grams} g CO² per 100g of product" +msgid "{grams} g CO₂e per 100g of product" +msgstr "{grams} g CO₂e per 100g of product" + +# variable names between { } must not be translated +msgctxt "f_carbon_footprint_per_unit" +msgid "{kilograms} kg CO₂e per unit" +msgstr "{kilograms} kg CO₂e per unit" + +msgctxt "average_for_the_category" +msgid "average for the category" +msgstr "average for the category" + +msgctxt "data_source_and_detailed_carbon_impact" +msgid "Data source and detailed carbon impact" +msgstr "Data source and detailed carbon impact" # variable names between { } must not be translated msgctxt "f_equal_to_driving_km_in_a_petrol_car" @@ -7105,3 +7118,81 @@ msgstr "Organization list" msgctxt "open_org" msgid "Open org" msgstr "Open org" + +msgctxt "secondhand" +msgid "Secondhand" +msgstr "Secondhand" + +msgctxt "donated_products_title" +msgid "Donations" +msgstr "Donations" + +msgctxt "donated_products_subtitle" +msgid "Give this product, or search for a similar donated product" +msgstr "Give this product, or search for a similar donated product" + +msgctxt "used_products_title" +msgid "Used products" +msgstr "Used products" + +msgctxt "used_products_subtitle" +msgid "Buy this product used, or search for a similar used product" +msgstr "Buy this product used, or search for a similar used product" + +msgctxt "attribute_repairability_index_france_name" +msgid "Repairability index" +msgstr "Repairability index" + +msgctxt "attribute_repairability_index_france_setting_name" +msgid "Good repairability" +msgstr "Good repairability" + +msgctxt "attribute_repairability_index_france_setting_note" +msgid "Mandatory rating in France for certain products since 2021" +msgstr "Mandatory rating in France for certain products since 2021" + +# keep %s, it will be replaced by the letter A, B, C, D or E +msgctxt "attribute_repairability_index_france_grade_title" +msgid "Repairability index %s" +msgstr "Repairability index %s" + +msgctxt "attribute_repairability_index_france_unknown_title" +msgid "Repairability index unknown" +msgstr "Repairability index unknown" + +msgctxt "attribute_repairability_index_france_not_applicable_title" +msgid "Repairability index not-applicable" +msgstr "Repairability index not-applicable" + +msgctxt "attribute_repairability_index_france_not_applicable_description_short" +msgid "Not-applicable for the category" +msgstr "Not-applicable for the category" + +# variable names between { } must not be translated +msgctxt "f_attribute_repairability_index_france_not_applicable_description" +msgid "Applicable only for categories: {categories}" +msgstr "Applicable only for categories: {categories}" + +msgctxt "attribute_repairability_index_france_very_good_description_short" +msgid "Very good repairability" +msgstr "Very good repairability" + +msgctxt "attribute_repairability_index_france_good_description_short" +msgid "Good repairability" +msgstr "Good repairability" + +msgctxt "attribute_repairability_index_france_average_description_short" +msgid "Average repairability" +msgstr "Average repairability" + +msgctxt "attribute_repairability_index_france_poor_description_short" +msgid "Poor repairability" +msgstr "Poor repairability" + +msgctxt "attribute_repairability_index_france_bad_description_short" +msgid "Bad repairability" +msgstr "Bad repairability" + +msgctxt "concerned_categories" +msgid "Bad repairability" +msgstr "Bad repairability" diff --git a/po/common/fr.po b/po/common/fr.po index 5263a15b4ab0f..3121f8de72bf8 100644 --- a/po/common/fr.po +++ b/po/common/fr.po @@ -4957,21 +4957,21 @@ msgctxt "ecoscore_information" msgid "Information about the Eco-score" msgstr "Information sur l'Eco-score" -msgctxt "preferences_edit_your_food_preferences" -msgid "Edit your food preferences" -msgstr "Modifier vos préférences alimentaires" - -msgctxt "preferences_your_preferences" -msgid "Your food preferences" -msgstr "Vos préférences alimentaires" - msgctxt "preferences_currently_selected_preferences" msgid "Currently selected preferences" msgstr "Préférences actuellement sélectionnées" msgctxt "preferences_locally_saved" -msgid "Your food preferences are kept in your browser and never sent to Open Food Facts or anyone else." -msgstr "Vos préférences alimentaires sont conservées dans votre navigateur et ne sont jamais envoyées à Open Food Facts ou à quiconque." +msgid "Your preferences are kept in your browser and never sent to Open Food Facts or anyone else." +msgstr "Vos préférences sont conservées dans votre navigateur et ne sont jamais envoyées à Open Food Facts ou à quiconque." + +msgctxt "preferences_edit_your_preferences" +msgid "Edit your preferences" +msgstr "Modifiez vos préférences" + +msgctxt "preferences_your_preferences" +msgid "Your preferences" +msgstr "Vos préférences" # used in phrases like "salt in unknown quantity" msgctxt "unknown_quantity" @@ -5802,8 +5802,21 @@ msgstr "Empreinte carbone" # variable names between { } must not be translated msgctxt "f_carbon_footprint_per_100g_of_product" -msgid "{grams} g CO² per 100g of product" -msgstr "{grams} g de CO² pour 100g de produit" +msgid "{grams} g CO₂e per 100g of product" +msgstr "{grams} g CO₂e pour 100g de produit" + +# variable names between { } must not be translated +msgctxt "f_carbon_footprint_per_unit" +msgid "{kilograms} kg CO₂e per unit" +msgstr "{kilograms} kg CO₂e par unité" + +msgctxt "average_for_the_category" +msgid "average for the category" +msgstr "moyenne pour la catégorie" + +msgctxt "data_source_and_detailed_carbon_impact" +msgid "Data source and detailed carbon impact" +msgstr "Source des données et détail de l'impact carbone" # variable names between { } must not be translated msgctxt "f_equal_to_driving_km_in_a_petrol_car" @@ -6962,4 +6975,79 @@ msgstr "Liste des organisations" msgctxt "open_org" msgid "Open org" -msgstr "Voir l'org" +msgstr "Voir l'org." + +msgctxt "secondhand" +msgid "Secondhand" +msgstr "Deuxième main" + +msgctxt "donated_products_title" +msgid "Donations" +msgstr "Dons" + +msgctxt "donated_products_subtitle" +msgid "Give this product, or search for a similar donated product" +msgstr "Donnez ce produit, ou recherchez un produit similaire donné" + +msgctxt "used_products_title" +msgid "Used products" +msgstr "Produits d'occasion" + +msgctxt "used_products_subtitle" +msgid "Buy this product used, or search for a similar used product" +msgstr "Achetez ce produit d'occasion, ou recherchez un produit d'occasion similaire" + +msgctxt "attribute_repairability_index_france_name" +msgid "Repairability index" +msgstr "Indice de réparabilité" + +msgctxt "attribute_repairability_index_france_setting_name" +msgid "Good repairability" +msgstr "Bonne réparabilité" + +msgctxt "attribute_repairability_index_france_setting_note" +msgid "Mandatory rating in France for certain products since 2021" +msgstr "Note sur 10 obligatoire en France pour certains produits depuis 2021" + +# keep %s, it will be replaced by the letter A, B, C, D or E +msgctxt "attribute_repairability_index_france_grade_title" +msgid "Repairability index %s" +msgstr "Indice de réparabilité %s" + +msgctxt "attribute_repairability_index_france_unknown_title" +msgid "repairability index unknown" +msgstr "Indice de réparabilité inconnu" + +msgctxt "attribute_repairability_index_france_not_applicable_title" +msgid "Repairability index not-applicable" +msgstr "Indice de réparabilité non applicable" + +msgctxt "attribute_repairability_index_france_not_applicable_description_short" +msgid "Not-applicable for the category" +msgstr "Non applicable pour la catégorie" + +# variable names between { } must not be translated +msgctxt "f_attribute_repairability_index_france_not_applicable_description" +msgid "Applicable only for categories: {categories}" +msgstr "Applicable seulement aux catégories : {categories}" + +msgctxt "attribute_repairability_index_france_very_good_description_short" +msgid "Very good repairability" +msgstr "Très bonne réparabilité" + +msgctxt "attribute_repairability_index_france_good_description_short" +msgid "Good repairability" +msgstr "Bonne réparabilité" + +msgctxt "attribute_repairability_index_france_average_description_short" +msgid "Average repairability" +msgstr "Moyenne réparabilité" + +msgctxt "attribute_repairability_index_france_poor_description_short" +msgid "Poor repairability" +msgstr "Mauvaise réparabilité" + +msgctxt "attribute_repairability_index_france_bad_description_short" +msgid "Bad repairability" +msgstr "Très mauvaise réparabilité" + diff --git a/scripts/migrations/2024_09_detect_duplicate_products.pl b/scripts/migrations/2024_09_detect_duplicate_products.pl new file mode 100755 index 0000000000000..714fa96b1292a --- /dev/null +++ b/scripts/migrations/2024_09_detect_duplicate_products.pl @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w + +# This file is part of Product Opener. +# +# Product Opener +# Copyright (C) 2011-2023 Association Open Food Facts +# Contact: contact@openfoodfacts.org +# Address: 21 rue des Iles, 94100 Saint-Maur des Fossés, France +# +# Product Opener is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +use Modern::Perl '2017'; +use utf8; + +use ProductOpener::Config qw/:all/; +use ProductOpener::Paths qw/%BASE_DIRS/; +use ProductOpener::Store qw/retrieve store/; +use ProductOpener::Data qw/get_products_collection/; + +use Log::Any::Adapter 'TAP'; + +my $socket_timeout_ms = 2 * 60000; # 2 mins, instead of 30s default, to not die as easily if mongodb is busy. + +my %flavors = (); + +foreach my $flavor ("off", "obf") { + my $products_collection = get_products_collection({database => $flavor, timeout => $socket_timeout_ms}); + + my $cursor = $products_collection->query({})->fields({_id => 1, code => 1, owner => 1}); + $cursor->immortal(1); + + while (my $product_ref = $cursor->next) { + $flavors{all}{$product_ref->{code}}++; + $flavors{$flavor}{$product_ref->{code}}++; + } +} + +foreach my $flavor (keys %flavors) { + print "Flavor $flavor\t" . scalar(keys %{$flavors{$flavor}}) . " products\n"; +} + diff --git a/scripts/update_all_products.pl b/scripts/update_all_products.pl index fc25fe850f3a1..56af909dd8696 100755 --- a/scripts/update_all_products.pl +++ b/scripts/update_all_products.pl @@ -151,6 +151,7 @@ my $obsolete = 0; my $fix_obsolete; my $fix_last_modified_t; # Will set the update key and ensure last_updated_t is initialised +my $add_product_type = ''; # Add product type to products that don't have it, based on off/opf/obf/opff flavor my $query_params_ref = {}; # filters for mongodb query @@ -212,6 +213,7 @@ "obsolete" => \$obsolete, "fix-obsolete" => \$fix_obsolete, "fix-last-modified-t" => \$fix_last_modified_t, + "add-product-type" => \$add_product_type, ) or die("Error in command line arguments:\n\n$usage"); use Data::Dumper; @@ -289,6 +291,7 @@ and (not $assign_ciqual_codes) and (not $fix_obsolete) and (not $fix_last_modified_t) + and (not $add_product_type) and (not $analyze_and_enrich_product_data)) { die("Missing fields to update or --count option:\n$usage"); @@ -1365,6 +1368,15 @@ } } + # Add product type + if (($add_product_type) and (not defined $product_ref->{product_type})) { + $product_ref->{product_type} = $options{product_type}; + # Silent update: we also change the original_product + # in order not to push the product to Redis + $original_product->{product_type} = $product_ref->{product_type}; + # $product_values_changed = 1; + } + if ($assign_ciqual_codes) { assign_ciqual_codes($product_ref); } diff --git a/stop_words.txt b/stop_words.txt index b505e2dedb4ae..08ca8af7ed42c 100644 --- a/stop_words.txt +++ b/stop_words.txt @@ -221,6 +221,7 @@ Prunus publique Pulpe reimplemented +repairability rescale Robotoff RTFSG diff --git a/taxonomies/petfood/categories.txt b/taxonomies/petfood/categories.txt index c0b19a769bb09..9c336359327bd 100755 --- a/taxonomies/petfood/categories.txt +++ b/taxonomies/petfood/categories.txt @@ -1,142 +1,140 @@ -en:Dry food -nl:Droog voedsel -nl_be:Droog voedsel -ru:Сухой корм - -en:Wet food -nl:Nat voedsel -nl_be:Nat voedsel - -en:Dog and cat food -de:Hunde- und Katzenfutter -fr:Nourriture pour chiens et chats -nl:Honden en kattenvoedsel -ru:Корм для собак и кошек - - "book". Used in particular for carbon footprint equivalent: 1 smartphone = 85.9 kg CO2e +# +# - carbon_impact_fr_impactco2:en: co2 equivalent in kg per unit (1 product) from https://impactco2.fr/ +# - carbon_impact_fr_impactco2_link:en: URL for the category on https://impactco2.fr/ + +en: Electronic products, electronics +fr: Appareils électroniques +secondhand_used:en: backmarket + +< en: electronic products +en: Digital tablets +fr: Tablettes numériques, tablette numérique +carbon_impact_fr_impactco2:en: 61.9 +carbon_impact_fr_impactco2_link:en: https://impactco2.fr/outils/numerique/tabletteclassique +unit_name:en: digital tablet +unit_name:fr: tablette numérique + +< en: electronic products +en: mobile phones, cell phones +fr: téléphones portables, téléphones mobiles + +< en: mobile phones +en: Smartphones +xx: Smartphones +carbon_impact_fr_impactco2:en: 85.9 +carbon_impact_fr_impactco2_link:en: https://impactco2.fr/outils/numerique/smartphone +unit_name:xx: smartphone +unit_name:en: smartphone + +< en: Smartphones +en: Android smartphones +fr: Smartphones Android + +< en: Smartphones +en: iPhone smartphones +xx: iPhone, iPhones +fr: Smartphones iPhone + +en: Clothes +fr: Vêtements + +< en: Clothes +en: T-shirts +xx: T-shirts, Tshirts, teeshirts, teeshirt +carbon_impact_fr_impactco2:en: 6.43 +carbon_impact_fr_impactco2_link:en: https://impactco2.fr/outils/habillement/tshirtencoton +unit_name:xx: t-shirt +unit_name:en: t-shirt + +en: Books +fr: Livres + +en: Papers +fr: Papiers + +< en: Papers +en: Origami papers, origami craft papers + +en: Toilet papers, toilet tissues, toilet rolls +fr: Papiers toilette, papier toilette, papier hygiénique, papiers hygiéniques + +en: Cigarettes +fr: Cigarettes + +en: Laundry detergents +fr: Lessives + diff --git a/taxonomies/product/labels.txt b/taxonomies/product/labels.txt new file mode 100644 index 0000000000000..b025785781154 --- /dev/null +++ b/taxonomies/product/labels.txt @@ -0,0 +1,410 @@ +# Labels specific for Open Product Facts (generic products: not food, pet food or beauty) + +# French reparability index + +# Labels specific for Open Product Facts (generic products: not food, pet food or beauty) + +# French reparability index + +en: Repairability index 0 - France +fr: Indice de réparabilité 0 +repairability_index_france_value:en: 0 + +en: Repairability index 0.1 - France +fr: Indice de réparabilité 0.1 +repairability_index_france_value:en: 0.1 + +en: Repairability index 0.2 - France +fr: Indice de réparabilité 0.2 +repairability_index_france_value:en: 0.2 + +en: Repairability index 0.3 - France +fr: Indice de réparabilité 0.3 +repairability_index_france_value:en: 0.3 + +en: Repairability index 0.4 - France +fr: Indice de réparabilité 0.4 +repairability_index_france_value:en: 0.4 + +en: Repairability index 0.5 - France +fr: Indice de réparabilité 0.5 +repairability_index_france_value:en: 0.5 + +en: Repairability index 0.6 - France +fr: Indice de réparabilité 0.6 +repairability_index_france_value:en: 0.6 + +en: Repairability index 0.7 - France +fr: Indice de réparabilité 0.7 +repairability_index_france_value:en: 0.7 + +en: Repairability index 0.8 - France +fr: Indice de réparabilité 0.8 +repairability_index_france_value:en: 0.8 + +en: Repairability index 0.9 - France +fr: Indice de réparabilité 0.9 +repairability_index_france_value:en: 0.9 + +en: Repairability index 1.0 - France +fr: Indice de réparabilité 1.0 +repairability_index_france_value:en: 1.0 + +en: Repairability index 1.1 - France +fr: Indice de réparabilité 1.1 +repairability_index_france_value:en: 1.1 + +en: Repairability index 1.2 - France +fr: Indice de réparabilité 1.2 +repairability_index_france_value:en: 1.2 + +en: Repairability index 1.3 - France +fr: Indice de réparabilité 1.3 +repairability_index_france_value:en: 1.3 + +en: Repairability index 1.4 - France +fr: Indice de réparabilité 1.4 +repairability_index_france_value:en: 1.4 + +en: Repairability index 1.5 - France +fr: Indice de réparabilité 1.5 +repairability_index_france_value:en: 1.5 + +en: Repairability index 1.6 - France +fr: Indice de réparabilité 1.6 +repairability_index_france_value:en: 1.6 + +en: Repairability index 1.7 - France +fr: Indice de réparabilité 1.7 +repairability_index_france_value:en: 1.7 + +en: Repairability index 1.8 - France +fr: Indice de réparabilité 1.8 +repairability_index_france_value:en: 1.8 + +en: Repairability index 1.9 - France +fr: Indice de réparabilité 1.9 +repairability_index_france_value:en: 1.9 + +en: Repairability index 2.0 - France +fr: Indice de réparabilité 2.0 +repairability_index_france_value:en: 2.0 + +en: Repairability index 2.1 - France +fr: Indice de réparabilité 2.1 +repairability_index_france_value:en: 2.1 + +en: Repairability index 2.2 - France +fr: Indice de réparabilité 2.2 +repairability_index_france_value:en: 2.2 + +en: Repairability index 2.3 - France +fr: Indice de réparabilité 2.3 +repairability_index_france_value:en: 2.3 + +en: Repairability index 2.4 - France +fr: Indice de réparabilité 2.4 +repairability_index_france_value:en: 2.4 + +en: Repairability index 2.5 - France +fr: Indice de réparabilité 2.5 +repairability_index_france_value:en: 2.5 + +en: Repairability index 2.6 - France +fr: Indice de réparabilité 2.6 +repairability_index_france_value:en: 2.6 + +en: Repairability index 2.7 - France +fr: Indice de réparabilité 2.7 +repairability_index_france_value:en: 2.7 + +en: Repairability index 2.8 - France +fr: Indice de réparabilité 2.8 +repairability_index_france_value:en: 2.8 + +en: Repairability index 2.9 - France +fr: Indice de réparabilité 2.9 +repairability_index_france_value:en: 2.9 + +en: Repairability index 3.0 - France +fr: Indice de réparabilité 3.0 +repairability_index_france_value:en: 3.0 + +en: Repairability index 3.1 - France +fr: Indice de réparabilité 3.1 +repairability_index_france_value:en: 3.1 + +en: Repairability index 3.2 - France +fr: Indice de réparabilité 3.2 +repairability_index_france_value:en: 3.2 + +en: Repairability index 3.3 - France +fr: Indice de réparabilité 3.3 +repairability_index_france_value:en: 3.3 + +en: Repairability index 3.4 - France +fr: Indice de réparabilité 3.4 +repairability_index_france_value:en: 3.4 + +en: Repairability index 3.5 - France +fr: Indice de réparabilité 3.5 +repairability_index_france_value:en: 3.5 + +en: Repairability index 3.6 - France +fr: Indice de réparabilité 3.6 +repairability_index_france_value:en: 3.6 + +en: Repairability index 3.7 - France +fr: Indice de réparabilité 3.7 +repairability_index_france_value:en: 3.7 + +en: Repairability index 3.8 - France +fr: Indice de réparabilité 3.8 +repairability_index_france_value:en: 3.8 + +en: Repairability index 3.9 - France +fr: Indice de réparabilité 3.9 +repairability_index_france_value:en: 3.9 + +en: Repairability index 4.0 - France +fr: Indice de réparabilité 4.0 +repairability_index_france_value:en: 4.0 + +en: Repairability index 4.1 - France +fr: Indice de réparabilité 4.1 +repairability_index_france_value:en: 4.1 + +en: Repairability index 4.2 - France +fr: Indice de réparabilité 4.2 +repairability_index_france_value:en: 4.2 + +en: Repairability index 4.3 - France +fr: Indice de réparabilité 4.3 +repairability_index_france_value:en: 4.3 + +en: Repairability index 4.4 - France +fr: Indice de réparabilité 4.4 +repairability_index_france_value:en: 4.4 + +en: Repairability index 4.5 - France +fr: Indice de réparabilité 4.5 +repairability_index_france_value:en: 4.5 + +en: Repairability index 4.6 - France +fr: Indice de réparabilité 4.6 +repairability_index_france_value:en: 4.6 + +en: Repairability index 4.7 - France +fr: Indice de réparabilité 4.7 +repairability_index_france_value:en: 4.7 + +en: Repairability index 4.8 - France +fr: Indice de réparabilité 4.8 +repairability_index_france_value:en: 4.8 + +en: Repairability index 4.9 - France +fr: Indice de réparabilité 4.9 +repairability_index_france_value:en: 4.9 + +en: Repairability index 5.0 - France +fr: Indice de réparabilité 5.0 +repairability_index_france_value:en: 5.0 + +en: Repairability index 5.1 - France +fr: Indice de réparabilité 5.1 +repairability_index_france_value:en: 5.1 + +en: Repairability index 5.2 - France +fr: Indice de réparabilité 5.2 +repairability_index_france_value:en: 5.2 + +en: Repairability index 5.3 - France +fr: Indice de réparabilité 5.3 +repairability_index_france_value:en: 5.3 + +en: Repairability index 5.4 - France +fr: Indice de réparabilité 5.4 +repairability_index_france_value:en: 5.4 + +en: Repairability index 5.5 - France +fr: Indice de réparabilité 5.5 +repairability_index_france_value:en: 5.5 + +en: Repairability index 5.6 - France +fr: Indice de réparabilité 5.6 +repairability_index_france_value:en: 5.6 + +en: Repairability index 5.7 - France +fr: Indice de réparabilité 5.7 +repairability_index_france_value:en: 5.7 + +en: Repairability index 5.8 - France +fr: Indice de réparabilité 5.8 +repairability_index_france_value:en: 5.8 + +en: Repairability index 5.9 - France +fr: Indice de réparabilité 5.9 +repairability_index_france_value:en: 5.9 + +en: Repairability index 6.0 - France +fr: Indice de réparabilité 6.0 +repairability_index_france_value:en: 6.0 + +en: Repairability index 6.1 - France +fr: Indice de réparabilité 6.1 +repairability_index_france_value:en: 6.1 + +en: Repairability index 6.2 - France +fr: Indice de réparabilité 6.2 +repairability_index_france_value:en: 6.2 + +en: Repairability index 6.3 - France +fr: Indice de réparabilité 6.3 +repairability_index_france_value:en: 6.3 + +en: Repairability index 6.4 - France +fr: Indice de réparabilité 6.4 +repairability_index_france_value:en: 6.4 + +en: Repairability index 6.5 - France +fr: Indice de réparabilité 6.5 +repairability_index_france_value:en: 6.5 + +en: Repairability index 6.6 - France +fr: Indice de réparabilité 6.6 +repairability_index_france_value:en: 6.6 + +en: Repairability index 6.7 - France +fr: Indice de réparabilité 6.7 +repairability_index_france_value:en: 6.7 + +en: Repairability index 6.8 - France +fr: Indice de réparabilité 6.8 +repairability_index_france_value:en: 6.8 + +en: Repairability index 6.9 - France +fr: Indice de réparabilité 6.9 +repairability_index_france_value:en: 6.9 + +en: Repairability index 7.0 - France +fr: Indice de réparabilité 7.0 +repairability_index_france_value:en: 7.0 + +en: Repairability index 7.1 - France +fr: Indice de réparabilité 7.1 +repairability_index_france_value:en: 7.1 + +en: Repairability index 7.2 - France +fr: Indice de réparabilité 7.2 +repairability_index_france_value:en: 7.2 + +en: Repairability index 7.3 - France +fr: Indice de réparabilité 7.3 +repairability_index_france_value:en: 7.3 + +en: Repairability index 7.4 - France +fr: Indice de réparabilité 7.4 +repairability_index_france_value:en: 7.4 + +en: Repairability index 7.5 - France +fr: Indice de réparabilité 7.5 +repairability_index_france_value:en: 7.5 + +en: Repairability index 7.6 - France +fr: Indice de réparabilité 7.6 +repairability_index_france_value:en: 7.6 + +en: Repairability index 7.7 - France +fr: Indice de réparabilité 7.7 +repairability_index_france_value:en: 7.7 + +en: Repairability index 7.8 - France +fr: Indice de réparabilité 7.8 +repairability_index_france_value:en: 7.8 + +en: Repairability index 7.9 - France +fr: Indice de réparabilité 7.9 +repairability_index_france_value:en: 7.9 + +en: Repairability index 8.0 - France +fr: Indice de réparabilité 8.0 +repairability_index_france_value:en: 8.0 + +en: Repairability index 8.1 - France +fr: Indice de réparabilité 8.1 +repairability_index_france_value:en: 8.1 + +en: Repairability index 8.2 - France +fr: Indice de réparabilité 8.2 +repairability_index_france_value:en: 8.2 + +en: Repairability index 8.3 - France +fr: Indice de réparabilité 8.3 +repairability_index_france_value:en: 8.3 + +en: Repairability index 8.4 - France +fr: Indice de réparabilité 8.4 +repairability_index_france_value:en: 8.4 + +en: Repairability index 8.5 - France +fr: Indice de réparabilité 8.5 +repairability_index_france_value:en: 8.5 + +en: Repairability index 8.6 - France +fr: Indice de réparabilité 8.6 +repairability_index_france_value:en: 8.6 + +repairability_index_france_value:en: 8.7 + +en: Repairability index 8.8 - France +fr: Indice de réparabilité 8.8 +repairability_index_france_value:en: 8.8 + +en: Repairability index 8.9 - France +fr: Indice de réparabilité 8.9 +repairability_index_france_value:en: 8.9 + +en: Repairability index 9.0 - France +fr: Indice de réparabilité 9.0 +repairability_index_france_value:en: 9.0 + +en: Repairability index 9.1 - France +fr: Indice de réparabilité 9.1 +repairability_index_france_value:en: 9.1 + +en: Repairability index 9.2 - France +fr: Indice de réparabilité 9.2 +repairability_index_france_value:en: 9.2 + +en: Repairability index 9.3 - France +fr: Indice de réparabilité 9.3 +repairability_index_france_value:en: 9.3 + +en: Repairability index 9.4 - France +fr: Indice de réparabilité 9.4 +repairability_index_france_value:en: 9.4 + +en: Repairability index 9.5 - France +fr: Indice de réparabilité 9.5 +repairability_index_france_value:en: 9.5 + +en: Repairability index 9.6 - France +fr: Indice de réparabilité 9.6 +repairability_index_france_value:en: 9.6 + +en: Repairability index 9.7 - France +fr: Indice de réparabilité 9.7 +repairability_index_france_value:en: 9.7 + +en: Repairability index 9.8 - France +fr: Indice de réparabilité 9.8 +repairability_index_france_value:en: 9.8 + +en: Repairability index 9.9 - France +fr: Indice de réparabilité 9.9 +repairability_index_france_value:en: 9.9 + +en: Repairability index 10 - France +fr: Indice de réparabilité 10 +repairability_index_france_value:en: 10 + diff --git a/taxonomies/test.txt b/taxonomies/test.txt index 306f3afdc3ba7..a13b180085932 100644 --- a/taxonomies/test.txt +++ b/taxonomies/test.txt @@ -123,5 +123,9 @@ de: Special value for German 3 sv: Ä-märket xx: Ä-märket +en: Smartphones +xx: Smartphones +fr: Téléphones intelligents + en: Entry with (parentheses) and some *!#{}@$ characters, synonym with *%@$(]% chars diff --git a/templates/api/knowledge-panels/environment/carbon_footprint.tt.json b/templates/api/knowledge-panels/environment/carbon_footprint_food.tt.json similarity index 100% rename from templates/api/knowledge-panels/environment/carbon_footprint.tt.json rename to templates/api/knowledge-panels/environment/carbon_footprint_food.tt.json diff --git a/templates/api/knowledge-panels/environment/carbon_footprint_product.tt.json b/templates/api/knowledge-panels/environment/carbon_footprint_product.tt.json new file mode 100644 index 0000000000000..725521cc409e0 --- /dev/null +++ b/templates/api/knowledge-panels/environment/carbon_footprint_product.tt.json @@ -0,0 +1,35 @@ +[% SET driving_per_unit = panel.co2_kg_per_unit * 100 / 19.3 %] +[% SET driving_per_unit_rounded = sprintf('%.1f', driving_per_unit) %] +[% SET co2_kg_per_unit_rounded = sprintf('%.1f', panel.co2_kg_per_unit) %] +{ + "level" :"info", + "topics": [ + "environment" + ], + "expanded": false, + "title_element": { + "title": "1 [% panel.unit_name %] = [% co2_kg_per_unit_rounded %] kg CO₂e", + "subtitle": "[% edq(lang("average_for_the_category").ucfirst) %][% sep %]: [% panel.category_name %]", + "icon_url": "[% static_subdomain %]/images/panels/fr-impact-co2/impact-co2.svg", + }, + "elements": [ + { + "element_type": "text", + "text_element": { + "type": "summary", + "html": ` +

[% edq(f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_per_unit_rounded } )) %]

+

[% lang("data_source_and_detailed_carbon_impact") %][% sep %]: Impact CO2 - Catégorie: [% panel.category_name %]

+ ` + } + }, + { + "element_type": "image", + "image_element": { + "url": "[% static_subdomain %]/images/panels/fr-impact-co2/republique-francaise-ademe-impact-co2.svg", + "alt": "Impact CO2", + "link_url": "[% panel.link %]" + } + }, + ] +} \ No newline at end of file diff --git a/templates/api/knowledge-panels/environment/environment_card.tt.json b/templates/api/knowledge-panels/environment/environment_card.tt.json index c9c953d85a19b..04d88db8ae01f 100644 --- a/templates/api/knowledge-panels/environment/environment_card.tt.json +++ b/templates/api/knowledge-panels/environment/environment_card.tt.json @@ -46,16 +46,18 @@ }, }, [% END %] + [% IF panels.manufacturing_place.defined OR panels.origins_of_ingredients.defined %] { "element_type": "panel_group", "panel_group_element": { "title": "[% edq(lang('ecoscore_transportation')) %]", "panel_ids": [ [% IF panels.manufacturing_place.defined %]"manufacturing_place",[% END %] - "origins_of_ingredients", + [% IF panels.origins_of_ingredients.defined %]"origins_of_ingredients",[% END %] ], }, - }, + }, + [% END %] [% IF panels.palm_oil.defined %] { "element_type": "panel_group", diff --git a/templates/api/knowledge-panels/environment/packaging_recycling.tt.json b/templates/api/knowledge-panels/environment/packaging_recycling.tt.json index f60f97f2eba25..4f1d235f7fae7 100644 --- a/templates/api/knowledge-panels/environment/packaging_recycling.tt.json +++ b/templates/api/knowledge-panels/environment/packaging_recycling.tt.json @@ -3,7 +3,7 @@ "topics": [ "environment" ], -[% IF NOT (product.ecoscore_data.adjustments.packaging.packagings AND product.ecoscore_data.adjustments.packaging.packagings.size) %] +[% IF NOT (product.packagings.size) %] "evaluation": "unknown", "title_element": { "title": "[% edq(lang('ecoscore_packaging_missing_information')) %]", @@ -31,8 +31,15 @@ } }, ], -[% ELSE %] - [% IF product.ecoscore_data.adjustments.packaging.value <= -15 %] +[% ELSE %] + // Eco-Score currently computed only for food products + // no evaluation of packaging for other product types + // TODO: add evaluation for non-food products + [% IF NOT product.ecoscore_data.adjustments.packaging.value.defined %] + "evaluation": "unknown", + "title_element": { + "title": "[% edq(lang('packaging')) %]", + [% ELSIF product.ecoscore_data.adjustments.packaging.value <= -15 %] "evaluation": "bad", "title_element": { "title": "[% edq(lang('ecoscore_packaging_impact_high')) %]", diff --git a/templates/api/knowledge-panels/root.tt.json b/templates/api/knowledge-panels/root.tt.json index 6b6310e9faec3..d10e7d5cc4f77 100644 --- a/templates/api/knowledge-panels/root.tt.json +++ b/templates/api/knowledge-panels/root.tt.json @@ -18,6 +18,14 @@ }, }, [% END %] + [% IF panel.has_secondhand_card %] + { + "element_type": "panel", + "panel_element": { + "panel_id": "secondhand_card", + }, + }, + [% END %] [% IF panel.has_report_problem_card %] { "element_type": "panel", diff --git a/templates/api/knowledge-panels/secondhand/donated_products.tt.json b/templates/api/knowledge-panels/secondhand/donated_products.tt.json new file mode 100644 index 0000000000000..014ac7a09b96d --- /dev/null +++ b/templates/api/knowledge-panels/secondhand/donated_products.tt.json @@ -0,0 +1,33 @@ +{ + "level": "info", + "topics": [ + "secondhand" + ], + "expand_for": "large", + "title_element": { + "title": "[% edq(lang('donated_products_title')) %]", + "subtitle": "[% edq(lang('donated_products_subtitle')) %]", + //"icon_url": "[% static_subdomain %]/images/panels/report_problem/signalconso.png", + }, + "elements": [ + [% IF cc == 'fr' %] + // In France, display the donated_products_fr_geev panel + { + "element_type": "panel", + "panel_element": { + "panel_id": "donated_products_fr_geev", + }, + }, + [% ELSE %] + // In other countries, display a message that we don't have donation options yet + { + "element_type": "text", + "text_element": { + "html": ` +

Donation options are not yet available in your country.

+ ` + }, + }, + [% END %] + ] +} diff --git a/templates/api/knowledge-panels/secondhand/donated_products_fr_geev.tt.json b/templates/api/knowledge-panels/secondhand/donated_products_fr_geev.tt.json new file mode 100644 index 0000000000000..4a6d89275fb7a --- /dev/null +++ b/templates/api/knowledge-panels/secondhand/donated_products_fr_geev.tt.json @@ -0,0 +1,25 @@ +{ + "level": "info", + "topics": [ + "secondhand" + ], + "expand_for": "large", + "title_element": { + "title": "Donner ce produit ou rechercher un produit similaire sur Geev", + //"subtitle": "", + "icon_url": "[% static_subdomain %]/images/panels/secondhand/geev.200x100.svg", + }, + "elements": [ + { + "element_type": "text", + "text_element": { + "html": ` +

Vous pouvez donner ce produit sur Geev, une application mobile qui permet de donner et de récupérer des objets gratuitement.

+
    +
  • Chercher le produit "[% product.product_name %]" sur Geev
  • +
  • Chercher la catégorie "[% panel.category_name %]" sur Geev
  • + ` + }, + }, + ] +} diff --git a/templates/api/knowledge-panels/secondhand/secondhand_card.tt.json b/templates/api/knowledge-panels/secondhand/secondhand_card.tt.json new file mode 100644 index 0000000000000..aa8519452bf86 --- /dev/null +++ b/templates/api/knowledge-panels/secondhand/secondhand_card.tt.json @@ -0,0 +1,28 @@ +{ + "type": "card", + "expanded": true, + "topics": [ + "secondhand" + ], + "title_element": { + "title": "[% edq(lang('secondhand')) %]", + }, + "elements": [ + [% IF panels.donated_products.defined %] + { + "element_type": "panel", + "panel_element": { + "panel_id": "donated_products", + }, + }, + [% END %] + [% IF panels.used_products.defined %] + { + "element_type": "panel", + "panel_element": { + "panel_id": "used_products", + }, + }, + [% END %] + ], +} diff --git a/templates/api/knowledge-panels/secondhand/used_products.tt.json b/templates/api/knowledge-panels/secondhand/used_products.tt.json new file mode 100644 index 0000000000000..1e208f665537e --- /dev/null +++ b/templates/api/knowledge-panels/secondhand/used_products.tt.json @@ -0,0 +1,32 @@ +{ + "level": "info", + "topics": [ + "secondhand" + ], + "expand_for": "large", + "title_element": { + "title": "[% lang('used_products_title') %]", + "subtitle": "[% lang('used_products_subtitle') %]", + //"icon_url": "[% static_subdomain %]/images/panels/report_problem/signalconso.png", + }, + "elements": [ + [% IF cc == 'fr' %] + { + "element_type": "panel", + "panel_element": { + "panel_id": "used_products_fr_backmarket", + }, + }, + [% ELSE %] + // In other countries, display a message that we don't have donation options yet + { + "element_type": "text", + "text_element": { + "html": ` +

    Used product options are not yet available in your country.

    + ` + }, + }, + [% END %] + ] +} diff --git a/templates/api/knowledge-panels/secondhand/used_products_fr_backmarket.tt.json b/templates/api/knowledge-panels/secondhand/used_products_fr_backmarket.tt.json new file mode 100644 index 0000000000000..59772d801cc7f --- /dev/null +++ b/templates/api/knowledge-panels/secondhand/used_products_fr_backmarket.tt.json @@ -0,0 +1,24 @@ +{ + "level": "info", + "topics": [ + "secondhand" + ], + "expand_for": "large", + "title_element": { + "title": "Acheter ce produit ou un produit similaire sur Back Market", + //"subtitle": "", + "icon_url": "[% static_subdomain %]/images/panels/secondhand/backmarket.200x100.svg", + }, + "elements": [ + { + "element_type": "text", + "text_element": { + "html": ` +
      +
    • Chercher le produit "[% product.product_name %]" sur Backmarket
    • +
    • Chercher la catégorie "[% panel.category_name %]" sur Backmarket
    • + ` + }, + }, + ] +} diff --git a/templates/web/common/site_layout.tt.html b/templates/web/common/site_layout.tt.html index 75e7b13b7ca49..ce91b88bf64f6 100644 --- a/templates/web/common/site_layout.tt.html +++ b/templates/web/common/site_layout.tt.html @@ -15,6 +15,7 @@ [% og_images2 %] [% options_favicons %] + diff --git a/templates/web/pages/product/product_page.tt.html b/templates/web/pages/product/product_page.tt.html index e6dc89d5347f7..dedee2d8fc036 100755 --- a/templates/web/pages/product/product_page.tt.html +++ b/templates/web/pages/product/product_page.tt.html @@ -90,6 +90,9 @@

      [% title %]

    • [% lang("health") %]
    • [% END %]
    • [% lang("environment") %]
    • + [% IF secondhand_card_panel %] +
    • [% lang("secondhand") %]
    • + [% END %] [% IF report_problem_card_panel %]
    • [% lang("report_problem_navigation") %]
    • [% END %] @@ -270,6 +273,19 @@

      [% lang('product_other_in [% END %] + +[% IF secondhand_card_panel %] +
      +
      +
      +
      + [% secondhand_card_panel %] +
      +
      +
      +
      +[% END %] + [% IF ! server_options_producers_platform %]
      diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-auth-bad-user-password.html b/tests/integration/expected_test_results/api_v2_product_read/get-auth-bad-user-password.html index aaa6192c5d775..3d090d09395ac 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-auth-bad-user-password.html +++ b/tests/integration/expected_test_results/api_v2_product_read/get-auth-bad-user-password.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-existing-product.json b/tests/integration/expected_test_results/api_v2_product_read/get-existing-product.json index 36d54dc82eeae..714a81b2eea8d 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-existing-product.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-existing-product.json @@ -1085,6 +1085,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-all-knowledge-panels.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-all-knowledge-panels.json index 0aacd40624ab5..d2513ff85b59a 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-all-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-all-knowledge-panels.json @@ -808,7 +808,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ @@ -2686,6 +2686,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-all.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-all.json index b5e41f3e4c9d4..61dd7851de808 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-all.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-all.json @@ -1085,6 +1085,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-attribute-groups-all-knowledge-panels.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-attribute-groups-all-knowledge-panels.json index 01e39b53ea49b..c249ed5e35f3f 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-attribute-groups-all-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-attribute-groups-all-knowledge-panels.json @@ -1456,7 +1456,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ @@ -3334,6 +3334,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json index 314aa78ab6eba..ba8edd1156661 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json @@ -116,7 +116,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json index bae030cbee78a..8adc90f9d7e4a 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json @@ -116,7 +116,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-fields-raw.json b/tests/integration/expected_test_results/api_v2_product_read/get-fields-raw.json index 4d55c192fb3be..af48be2a50343 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-fields-raw.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-fields-raw.json @@ -1080,6 +1080,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels-fr.json b/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels-fr.json index 5c5479aae1b1f..69524c29682ef 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels-fr.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels-fr.json @@ -116,7 +116,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g de CO² pour 100g de produit", + "subtitle" : "286 g CO₂e pour 100g de produit", "title" : "Équivaut à parcourir 1.5 km dans une voiture à essence" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels.json b/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels.json index c219f221eaf74..e51465648fc5e 100644 --- a/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v2_product_read/get-knowledge-panels.json @@ -116,7 +116,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v2_product_write/get-product-auth-good-password.json b/tests/integration/expected_test_results/api_v2_product_write/get-product-auth-good-password.json index bbc069a2636fa..31bb160923001 100644 --- a/tests/integration/expected_test_results/api_v2_product_write/get-product-auth-good-password.json +++ b/tests/integration/expected_test_results/api_v2_product_write/get-product-auth-good-password.json @@ -878,6 +878,7 @@ "product_name_fr" : "Product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_write/get-product-ingredients-text-without-language.json b/tests/integration/expected_test_results/api_v2_product_write/get-product-ingredients-text-without-language.json index 1870fa4d97df4..2aea2f4c09ac1 100644 --- a/tests/integration/expected_test_results/api_v2_product_write/get-product-ingredients-text-without-language.json +++ b/tests/integration/expected_test_results/api_v2_product_write/get-product-ingredients-text-without-language.json @@ -751,6 +751,7 @@ "product_name_en" : "Some sausages", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_write/get-product.json b/tests/integration/expected_test_results/api_v2_product_write/get-product.json index 0f33f2973b4cf..c556cc3673fcc 100644 --- a/tests/integration/expected_test_results/api_v2_product_write/get-product.json +++ b/tests/integration/expected_test_results/api_v2_product_write/get-product.json @@ -876,6 +876,7 @@ "product_name_fr" : "Product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v2_product_write/post-product-auth-bad-user-password.html b/tests/integration/expected_test_results/api_v2_product_write/post-product-auth-bad-user-password.html index c09660949d982..2edacccf14541 100644 --- a/tests/integration/expected_test_results/api_v2_product_write/post-product-auth-bad-user-password.html +++ b/tests/integration/expected_test_results/api_v2_product_write/post-product-auth-bad-user-password.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json index dda39bc5518a7..41edfdb936d4b 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-caret.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-caret.json index 80dd2095d858e..f027166b62e17 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-caret.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-caret.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-data-uri.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-data-uri.json index 80dd2095d858e..f027166b62e17 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-data-uri.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-data-uri.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json index dda39bc5518a7..41edfdb936d4b 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json index 80dd2095d858e..f027166b62e17 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json index 1d726f24acc1c..439d9c7276177 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json index f71402411e0d1..d2942dbab9d7a 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json @@ -810,7 +810,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ @@ -2712,6 +2712,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json index 06f6dda1ef743..8dd7c7c15bcf3 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json @@ -1111,6 +1111,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-attribute-groups-all-knowledge-panels.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-attribute-groups-all-knowledge-panels.json index f93d46e79145a..c666effcfd87e 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-attribute-groups-all-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-attribute-groups-all-knowledge-panels.json @@ -1458,7 +1458,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ @@ -3360,6 +3360,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json index cd4176e62ae02..64ad6e18a3027 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card-knowledge_panels_excluded-health_card.json @@ -117,7 +117,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json index 14873a821c9d9..46181d624ef02 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-knowledge-panels-knowledge-panels_included-health_card-environment_card.json @@ -117,7 +117,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-raw.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-raw.json index 7bbb42d1af87b..8fae953dcdcf3 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-raw.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-raw.json @@ -1082,6 +1082,7 @@ "product_name_en" : "Some product", "product_quantity" : "100", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels-fr.json b/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels-fr.json index a1e8d5e35462a..508fb0d1d6eae 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels-fr.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels-fr.json @@ -117,7 +117,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g de CO² pour 100g de produit", + "subtitle" : "286 g CO₂e pour 100g de produit", "title" : "Équivaut à parcourir 1.5 km dans une voiture à essence" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels.json b/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels.json index dceec648aa963..2428ef11aeee0 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-knowledge-panels.json @@ -117,7 +117,7 @@ "title_element" : { "icon_color_from_evaluation" : true, "icon_url" : "http://static.openfoodfacts.localhost/images/icons/dist/car.svg", - "subtitle" : "286 g CO² per 100g of product", + "subtitle" : "286 g CO₂e per 100g of product", "title" : "Equal to driving 1.5 km in a petrol car" }, "topics" : [ diff --git a/tests/integration/expected_test_results/api_v3_product_write/patch-request-fields-all.json b/tests/integration/expected_test_results/api_v3_product_write/patch-request-fields-all.json index 5595ac131cb2f..e76f9f59968dc 100644 --- a/tests/integration/expected_test_results/api_v3_product_write/patch-request-fields-all.json +++ b/tests/integration/expected_test_results/api_v3_product_write/patch-request-fields-all.json @@ -479,6 +479,7 @@ "missing-category" ], "popularity_key" : 0, + "product_type" : "food", "removed_countries_tags" : [], "rev" : 5, "states" : "en:empty, en:to-be-completed, en:nutrition-facts-to-be-completed, en:ingredients-to-be-completed, en:expiration-date-to-be-completed, en:packaging-code-to-be-completed, en:characteristics-to-be-completed, en:origins-to-be-completed, en:categories-to-be-completed, en:brands-to-be-completed, en:packaging-to-be-completed, en:quantity-to-be-completed, en:product-name-to-be-completed, en:photos-to-be-uploaded", diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070167470.json b/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070167470.json index c438689c39de6..433234a35add6 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070167470.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070167470.json @@ -563,6 +563,7 @@ "missing-category" ], "popularity_key" : 12, + "product_type" : "food", "removed_countries_tags" : [], "rev" : 5, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070815746.json b/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070815746.json index c2b71767fbbb7..319a222dbff0e 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070815746.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/carrefour-images/products/3560070815746.json @@ -601,6 +601,7 @@ "missing-category" ], "popularity_key" : 12, + "product_type" : "food", "removed_countries_tags" : [], "rev" : 8, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000838.json b/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000838.json index 713b1ce5e9bd0..802bcad16ee0c 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000838.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000838.json @@ -478,6 +478,7 @@ "product_name" : "A test product", "product_name_fr" : "A test product", "product_name_fr_imported" : "A test product", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000839.json b/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000839.json index 3619a51bfa58d..56d1dc36c01ad 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000839.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/openfoodfacts_import_template_fr_test/products/5228857000839.json @@ -510,6 +510,7 @@ "product_name" : "Another test product", "product_name_fr" : "Another test product", "product_name_fr_imported" : "Another test product", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "serving_size_value" : "33", diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390017165.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390017165.json index d4443b860195e..2add933ca99a2 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390017165.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390017165.json @@ -558,6 +558,7 @@ "product_name_fr_imported" : "Pate feuilletee deroulee", "product_quantity" : 230, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "230 g", "quantity_imported" : "230 g", "removed_countries_tags" : [], diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020745.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020745.json index 8ba3764bb4d34..bbac43f281fd5 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020745.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020745.json @@ -548,6 +548,7 @@ "product_name_fr_imported" : "Steak hache pur boeuf surgele 15% mg x10", "product_quantity" : 1000, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "1 kg", "quantity_imported" : "1 kg", "removed_countries_tags" : [], diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020806.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020806.json index ef6a5bb11a2c1..2135aed063c84 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020806.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020806.json @@ -520,6 +520,7 @@ "product_name" : "Boulettes au boeuf 750g jean roze", "product_name_fr" : "Boulettes au boeuf 750g jean roze", "product_name_fr_imported" : "Boulettes au boeuf 750g jean roze", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020998.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020998.json index 37eb6caa5bf3f..2e69f2fdde890 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020998.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390020998.json @@ -558,6 +558,7 @@ "product_name" : "Tarte aux fromages", "product_name_fr" : "Tarte aux fromages", "product_name_fr_imported" : "Tarte aux fromages", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021001.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021001.json index 02ca4937d34a4..c246a6765bc29 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021001.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021001.json @@ -540,6 +540,7 @@ "product_name" : "Burgers aux oignons x10 1kg", "product_name_fr" : "Burgers aux oignons x10 1kg", "product_name_fr_imported" : "Burgers aux oignons x10 1kg", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021469.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021469.json index b702c752aa6c7..cc2b38f9a7ff8 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021469.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021469.json @@ -537,6 +537,7 @@ "product_name" : "Cabillaud nature 4x100g", "product_name_fr" : "Cabillaud nature 4x100g", "product_name_fr_imported" : "Cabillaud nature 4x100g", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021544.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021544.json index 397741775a95b..e7f4d1f6810a7 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021544.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021544.json @@ -539,6 +539,7 @@ "product_name" : "Croquettes ail et fines herbes 6x50g", "product_name_fr" : "Croquettes ail et fines herbes 6x50g", "product_name_fr_imported" : "Croquettes ail et fines herbes 6x50g", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021568.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021568.json index da3c8bc510c10..3d90673f05584 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021568.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021568.json @@ -537,6 +537,7 @@ "product_name" : "15 Bâtonnets de poisson", "product_name_fr" : "15 Bâtonnets de poisson", "product_name_fr_imported" : "15 Bâtonnets de poisson", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021926.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021926.json index f77452104c1c2..6bb71926f6521 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021926.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390021926.json @@ -518,6 +518,7 @@ "product_name" : "Choux fleurs surgeles", "product_name_fr" : "Choux fleurs surgeles", "product_name_fr_imported" : "Choux fleurs surgeles", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024781.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024781.json index da0bf56940b37..138dcaffe1b5b 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024781.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024781.json @@ -584,6 +584,7 @@ "product_name" : "Colin d'alaska parisienne surgele", "product_name_fr" : "Colin d'alaska parisienne surgele", "product_name_fr_imported" : "Colin d'alaska parisienne surgele", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024804.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024804.json index 616ca12ceb7e0..ddb53c1e2a985 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024804.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024804.json @@ -568,6 +568,7 @@ "product_name" : "Colin d'alaska bordelaise", "product_name_fr" : "Colin d'alaska bordelaise", "product_name_fr_imported" : "Colin d'alaska bordelaise", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024842.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024842.json index ecf2432fc0249..5a6d0dffb9d05 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024842.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024842.json @@ -569,6 +569,7 @@ "product_name" : "Lasagne bolognaise surgelees", "product_name_fr" : "Lasagne bolognaise surgelees", "product_name_fr_imported" : "Lasagne bolognaise surgelees", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024866.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024866.json index 8140797a69d78..abb75ed9003fe 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024866.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390024866.json @@ -569,6 +569,7 @@ "product_name" : "Lasagnes bolognaise surgelees", "product_name_fr" : "Lasagnes bolognaise surgelees", "product_name_fr_imported" : "Lasagnes bolognaise surgelees", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025399.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025399.json index c14a7261f69da..59c8b7c167a8a 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025399.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025399.json @@ -559,6 +559,7 @@ "product_name" : "Tarte aux poireaux surgelée", "product_name_fr" : "Tarte aux poireaux surgelée", "product_name_fr_imported" : "Tarte aux poireaux surgelée", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025863.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025863.json index 6c807734d7d4e..dc1713bc4c5f2 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025863.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390025863.json @@ -517,6 +517,7 @@ "product_name" : "6 crepes jambon emmental", "product_name_fr" : "6 crepes jambon emmental", "product_name_fr_imported" : "6 crepes jambon emmental", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026044.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026044.json index dc85abf3e4ec0..061e70f1302f4 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026044.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026044.json @@ -558,6 +558,7 @@ "product_name" : "Adelie coupe cafe liegeois x4", "product_name_fr" : "Adelie coupe cafe liegeois x4", "product_name_fr_imported" : "Adelie coupe cafe liegeois x4", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026648.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026648.json index 591f52ddaeb7b..bf1c19d63884d 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026648.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026648.json @@ -585,6 +585,7 @@ "product_name" : "Colin d'alaska a la normande surgele", "product_name_fr" : "Colin d'alaska a la normande surgele", "product_name_fr_imported" : "Colin d'alaska a la normande surgele", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026754.json b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026754.json index bacf64d697bda..a7dedcf8f5333 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026754.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/packagings-mousquetaires/products/3250390026754.json @@ -551,6 +551,7 @@ "product_name" : "6 tomates farcies surgelées", "product_name_fr" : "6 tomates farcies surgelées", "product_name_fr_imported" : "6 tomates farcies surgelées", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/3270190128403.json b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/3270190128403.json index 9c90d46f2b651..fc9bb2f1d432d 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/3270190128403.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/3270190128403.json @@ -993,6 +993,7 @@ "product_name" : "Lentilles vertes Bio", "product_name_fr" : "Lentilles vertes Bio", "product_name_fr_imported" : "Lentilles vertes Bio", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 3, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/4270190128403.json b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/4270190128403.json index a831b54abfa70..923d03e68b0d1 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/4270190128403.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/4270190128403.json @@ -590,6 +590,7 @@ "popularity_key" : 0, "product_name_fr" : "Peaches", "product_name_fr_imported" : "Peaches", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/5270190128403.json b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/5270190128403.json index 07e0e310f115d..7b540205725d5 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/5270190128403.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/5270190128403.json @@ -606,6 +606,7 @@ "product_name" : "Super bananes", "product_name_fr" : "Super bananes", "product_name_fr_imported" : "Super bananes", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/7270190128403.json b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/7270190128403.json index 1d55d65efc038..0140d8d7259d8 100644 --- a/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/7270190128403.json +++ b/tests/integration/expected_test_results/convert_and_import_excel_file/test/products/7270190128403.json @@ -485,6 +485,7 @@ "producer_version_id_imported" : "Product will not be imported", "product_name_fr" : "Some product", "product_name_fr_imported" : "Some product", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006001.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006001.json index 63131164b1d5d..53c6c9f34ed43 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006001.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006001.json @@ -708,6 +708,7 @@ "product_name" : "Packagings fr", "product_name_fr" : "Packagings fr", "product_name_fr_imported" : "Packagings fr", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 2, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006002.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006002.json index 1f06e40ec8e36..ac8ae80c5aab1 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006002.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006002.json @@ -518,6 +518,7 @@ "product_name" : "Packagings fr virgule", "product_name_fr" : "Packagings fr virgule", "product_name_fr_imported" : "Packagings fr virgule", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 2, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006003.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006003.json index 3febb5dae4a0a..d94278adb1a2f 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006003.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006003.json @@ -515,6 +515,7 @@ "product_name" : "Packagings fr g", "product_name_fr" : "Packagings fr g", "product_name_fr_imported" : "Packagings fr g", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006004.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006004.json index bacba34888444..080b9f37c9848 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006004.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006004.json @@ -729,6 +729,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en", "product_name_fr_imported" : "Packagings en", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 2, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006005.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006005.json index 8d95a98ddbf24..84180a02edf9b 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006005.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006005.json @@ -543,6 +543,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - pot + lid", "product_name_fr_imported" : "Packagings en - pot + lid", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 2, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006006.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006006.json index bc8a77dc66c89..ccb7b6e58e693 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006006.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006006.json @@ -528,6 +528,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - pot + lid – incomplete", "product_name_fr_imported" : "Packagings en - pot + lid – incomplete", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 2, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006007.json b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006007.json index 9727047269749..96a81d1b13611 100644 --- a/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006007.json +++ b/tests/integration/expected_test_results/import_csv_file/replace_existing_values/3003004006007.json @@ -519,6 +519,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - several components of the same type", "product_name_fr_imported" : "Packagings en - several components of the same type", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006001.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006001.json index d447de1fc2514..0e804f59d620a 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006001.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006001.json @@ -702,6 +702,7 @@ "product_name" : "Packagings fr", "product_name_fr" : "Packagings fr", "product_name_fr_imported" : "Packagings fr", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006002.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006002.json index 4faa6f4abd739..bb707337b2b0f 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006002.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006002.json @@ -510,6 +510,7 @@ "product_name" : "Packagings fr virgule", "product_name_fr" : "Packagings fr virgule", "product_name_fr_imported" : "Packagings fr virgule", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006003.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006003.json index 5b103dc0f70bc..30ef6afc6997b 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006003.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006003.json @@ -515,6 +515,7 @@ "product_name" : "Packagings fr g", "product_name_fr" : "Packagings fr g", "product_name_fr_imported" : "Packagings fr g", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006004.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006004.json index f7cc7ee14a262..8a43b33f29fe0 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006004.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006004.json @@ -695,6 +695,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en", "product_name_fr_imported" : "Packagings en", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006005.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006005.json index 2750ac5af0ba2..86011157e5340 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006005.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006005.json @@ -535,6 +535,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - pot + lid", "product_name_fr_imported" : "Packagings en - pot + lid", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006006.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006006.json index 8597e917edd8a..33c97172f3482 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006006.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006006.json @@ -526,6 +526,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - pot + lid – incomplete", "product_name_fr_imported" : "Packagings en - pot + lid – incomplete", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/import_csv_file/test/2003004006007.json b/tests/integration/expected_test_results/import_csv_file/test/2003004006007.json index 91bde78f7e440..db220b11236ba 100644 --- a/tests/integration/expected_test_results/import_csv_file/test/2003004006007.json +++ b/tests/integration/expected_test_results/import_csv_file/test/2003004006007.json @@ -519,6 +519,7 @@ "popularity_key" : 0, "product_name_fr" : "Packagings en - several components of the same type", "product_name_fr_imported" : "Packagings en - several components of the same type", + "product_type" : "food", "removed_countries_tags" : [], "rev" : 1, "sources" : [ diff --git a/tests/integration/expected_test_results/page_crawler/crawler-access-category-facet-page.html b/tests/integration/expected_test_results/page_crawler/crawler-access-category-facet-page.html index 0b73d47dfcc0d..f8ada85d79d8d 100644 --- a/tests/integration/expected_test_results/page_crawler/crawler-access-category-facet-page.html +++ b/tests/integration/expected_test_results/page_crawler/crawler-access-category-facet-page.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -660,6 +658,7 @@

      Discover the project

      diff --git a/tests/integration/expected_test_results/page_crawler/crawler-does-not-get-facet-knowledge-panels.html b/tests/integration/expected_test_results/page_crawler/crawler-does-not-get-facet-knowledge-panels.html index 8d962038f4b55..9e088b8b44a74 100644 --- a/tests/integration/expected_test_results/page_crawler/crawler-does-not-get-facet-knowledge-panels.html +++ b/tests/integration/expected_test_results/page_crawler/crawler-does-not-get-facet-knowledge-panels.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -722,6 +720,7 @@

      Discover the project

      diff --git a/tests/integration/expected_test_results/page_crawler/normal-user-get-facet-knowledge-panels.html b/tests/integration/expected_test_results/page_crawler/normal-user-get-facet-knowledge-panels.html index 1d1c674a44a2e..d3e28ca8957d9 100644 --- a/tests/integration/expected_test_results/page_crawler/normal-user-get-facet-knowledge-panels.html +++ b/tests/integration/expected_test_results/page_crawler/normal-user-get-facet-knowledge-panels.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -763,6 +761,7 @@

      Discover the project

      diff --git a/tests/integration/expected_test_results/product_read/get-unexisting-product.html b/tests/integration/expected_test_results/product_read/get-unexisting-product.html index 4f059c0c950eb..33c52bc675458 100644 --- a/tests/integration/expected_test_results/product_read/get-unexisting-product.html +++ b/tests/integration/expected_test_results/product_read/get-unexisting-product.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form-moderator.html b/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form-moderator.html index d5bd86a79b672..f126839b8d731 100644 --- a/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form-moderator.html +++ b/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form-moderator.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form.html b/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form.html index 583e96f3cae25..651d2da7d0988 100644 --- a/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form.html +++ b/tests/integration/expected_test_results/protected_product/edit-protected-product-web-form.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/protected_product/edit-unprotected-product-web-form.html b/tests/integration/expected_test_results/protected_product/edit-unprotected-product-web-form.html index ccd21a56b1f3a..db607f9fb6923 100644 --- a/tests/integration/expected_test_results/protected_product/edit-unprotected-product-web-form.html +++ b/tests/integration/expected_test_results/protected_product/edit-unprotected-product-web-form.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2-moderator.json b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2-moderator.json index 40b495a92e9a3..15accb659632d 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2-moderator.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2-moderator.json @@ -857,6 +857,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 2, diff --git a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2.json b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2.json index d944b4da3e754..a6bb97488f5d4 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-api-v2.json @@ -858,6 +858,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "90", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "90g", "removed_countries_tags" : [], "rev" : 3, diff --git a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form-moderator.json b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form-moderator.json index 37ac7c7e854c4..651a69d6e7f2c 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form-moderator.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form-moderator.json @@ -861,6 +861,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 2, diff --git a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form.json b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form.json index 2c0b0d4fa0996..9f7400ce5f5dc 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-protected-product-web-form.json @@ -862,6 +862,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "90", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "90g", "removed_countries_tags" : [], "rev" : 3, diff --git a/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-api-v2.json b/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-api-v2.json index 9060c8208dab8..6ce3e728f1a14 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-api-v2.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-api-v2.json @@ -855,6 +855,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 2, diff --git a/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-web-form.json b/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-web-form.json index cf5c6262470fa..ccef86d33a2c5 100644 --- a/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-web-form.json +++ b/tests/integration/expected_test_results/protected_product/get-edited-unprotected-product-web-form.json @@ -859,6 +859,7 @@ "product_name_fr" : "New French product name", "product_quantity" : "250", "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "250 g", "removed_countries_tags" : [], "rev" : 2, diff --git a/tests/integration/expected_test_results/search_v1/search-no-filter.json b/tests/integration/expected_test_results/search_v1/search-no-filter.json index 81d1c3c16fb61..f3e86f5407c72 100644 --- a/tests/integration/expected_test_results/search_v1/search-no-filter.json +++ b/tests/integration/expected_test_results/search_v1/search-no-filter.json @@ -875,6 +875,7 @@ "product_name_en" : "test_1", "product_quantity" : 100, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, @@ -1489,6 +1490,7 @@ "product_name_en" : "vegan & palm oil free", "product_quantity" : 100, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, @@ -2321,6 +2323,7 @@ "product_name_en" : "palm oil free & non vegan", "product_quantity" : 100, "product_quantity_unit" : "ml", + "product_type" : "food", "quantity" : "100 ml", "removed_countries_tags" : [], "rev" : 1, @@ -3115,6 +3118,7 @@ "product_name_en" : "Vegan Test Snack with palm oil", "product_quantity" : 100, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, @@ -4069,6 +4073,7 @@ "product_name_en" : "Vegan breakfast cereals without palm oil", "product_quantity" : 100, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, @@ -5041,6 +5046,7 @@ "product_name_en" : "More vegan breakfast cereals without palm oil", "product_quantity" : 100, "product_quantity_unit" : "g", + "product_type" : "food", "quantity" : "100 g", "removed_countries_tags" : [], "rev" : 1, diff --git a/tests/integration/expected_test_results/unknown_tags/country-cambodia-exists-but-empty.html b/tests/integration/expected_test_results/unknown_tags/country-cambodia-exists-but-empty.html index 7b7e48f7c353b..d2681ddaf0025 100644 --- a/tests/integration/expected_test_results/unknown_tags/country-cambodia-exists-but-empty.html +++ b/tests/integration/expected_test_results/unknown_tags/country-cambodia-exists-but-empty.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -645,6 +643,7 @@

      Discover the project

      diff --git a/tests/integration/expected_test_results/web_html/fr-product.html b/tests/integration/expected_test_results/web_html/fr-product.html index c20f7dc137c2b..525b4e2a92696 100644 --- a/tests/integration/expected_test_results/web_html/fr-product.html +++ b/tests/integration/expected_test_results/web_html/fr-product.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -423,6 +421,7 @@

      Apple pie - Bob's pies
    • Santé
    • Environnement
    • +
    • Signaler un problème
    • @@ -2970,7 +2969,7 @@

      Empreinte carbone

      Équivaut à parcourir 0.9 km dans une voiture à essence

      - 169 g de CO² pour 100g de produit + 169 g CO₂e pour 100g de produit
      @@ -3534,6 +3533,9 @@

      Espèces menacées

      + + +
      @@ -3970,6 +3972,7 @@

      Découvrez le projet

      diff --git a/tests/integration/expected_test_results/web_html/fr-search-form.html b/tests/integration/expected_test_results/web_html/fr-search-form.html index 9ce6849f2f6dd..8df1e9c35a0d6 100644 --- a/tests/integration/expected_test_results/web_html/fr-search-form.html +++ b/tests/integration/expected_test_results/web_html/fr-search-form.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + diff --git a/tests/integration/expected_test_results/web_html/fr-search-results-cached.html b/tests/integration/expected_test_results/web_html/fr-search-results-cached.html index 0dadcafdfcfa5..a40988c7aa0aa 100644 --- a/tests/integration/expected_test_results/web_html/fr-search-results-cached.html +++ b/tests/integration/expected_test_results/web_html/fr-search-results-cached.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -638,6 +636,7 @@

      Découvrez le projet

      diff --git a/tests/integration/expected_test_results/web_html/world-products-multiple-codes.html b/tests/integration/expected_test_results/web_html/world-products-multiple-codes.html index d429763c58f2f..3fe650da9c47b 100644 --- a/tests/integration/expected_test_results/web_html/world-products-multiple-codes.html +++ b/tests/integration/expected_test_results/web_html/world-products-multiple-codes.html @@ -14,19 +14,17 @@ - - - - - - - - + + + + + + + + - - - + @@ -519,6 +517,7 @@

      Discover the project