From f77eb8248504d17bbc1e1cb5130a4bdbccc931d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Gigandet?= Date: Thu, 28 Nov 2024 17:02:50 +0100 Subject: [PATCH] fix: pro platform product writes to the public platform MongoDB database (#11065) fixes #11064 debug notes in the issue: https://github.com/openfoodfacts/openfoodfacts-server/issues/11064#issuecomment-2506412589 --- cgi/product_jqm_multilingual.pl | 6 +++- cgi/product_multilingual.pl | 6 +++- lib/ProductOpener/APIProductRead.pm | 6 +++- lib/ProductOpener/APIProductWrite.pm | 6 +++- lib/ProductOpener/Config.pm | 6 +++- lib/ProductOpener/Display.pm | 19 +++++++++-- lib/ProductOpener/Products.pm | 50 +++++++++++++++++++++------- 7 files changed, 79 insertions(+), 20 deletions(-) diff --git a/cgi/product_jqm_multilingual.pl b/cgi/product_jqm_multilingual.pl index 7ce034b668e3a..059648b30289d 100755 --- a/cgi/product_jqm_multilingual.pl +++ b/cgi/product_jqm_multilingual.pl @@ -118,8 +118,12 @@ =head1 DESCRIPTION else { # There is an existing product # If the product has a product_type and it is not the product_type of the server, redirect to the correct server + # unless we are on the pro platform - if ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + if ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { redirect_to_url($request_ref, 307, format_subdomain($subdomain, $product_ref->{product_type}) . '/cgi/product_jqm.pl?code=' . $code); } diff --git a/cgi/product_multilingual.pl b/cgi/product_multilingual.pl index bbbd17fdabe8a..e86c5cdecef17 100755 --- a/cgi/product_multilingual.pl +++ b/cgi/product_multilingual.pl @@ -347,8 +347,12 @@ ($product_ref) else { # There is an existing product # If the product has a product_type and it is not the product_type of the server, redirect to the correct server + # unless we are on the pro platform # We use a 302 redirect so that browsers issue a GET request to display the form (even if we received a POST request) - if ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + if ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { redirect_to_url($request_ref, 302, format_subdomain($subdomain, $product_ref->{product_type}) . '/cgi/product.pl?code=' . $code); } diff --git a/lib/ProductOpener/APIProductRead.pm b/lib/ProductOpener/APIProductRead.pm index 87b2903587f92..ef272362b02f2 100644 --- a/lib/ProductOpener/APIProductRead.pm +++ b/lib/ProductOpener/APIProductRead.pm @@ -138,10 +138,14 @@ sub read_product_api ($request_ref) { ); $response_ref->{result} = {id => "product_not_found"}; } - elsif ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + elsif ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { # If the product has a product_type and it is not the product_type of the server, # redirect to the correct server if the request includes a matching product_type parameter (or the "all" product type) + # unless we are on the pro platform my $requested_product_type = single_param("product_type"); if ( (defined $requested_product_type) diff --git a/lib/ProductOpener/APIProductWrite.pm b/lib/ProductOpener/APIProductWrite.pm index 431e4e16bcd94..900afadb1b827 100644 --- a/lib/ProductOpener/APIProductWrite.pm +++ b/lib/ProductOpener/APIProductWrite.pm @@ -550,8 +550,12 @@ sub write_product_api ($request_ref) { else { # There is an existing product # If the product has a product_type and it is not the product_type of the server, redirect to the correct server + # unless we are on the pro platform - if ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + if ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { redirect_to_url($request_ref, 307, format_subdomain($subdomain, $product_ref->{product_type}) . '/api/v3/product/' . $code); } diff --git a/lib/ProductOpener/Config.pm b/lib/ProductOpener/Config.pm index 484946e1a714d..0dcb97c3aa0c3 100644 --- a/lib/ProductOpener/Config.pm +++ b/lib/ProductOpener/Config.pm @@ -163,10 +163,14 @@ $ProductOpener::Config::options{other_servers} = { domain => "openproductsfacts.org", }, opff => { - prefix => "opff", name => "Open Pet Food Facts", mongodb => "opff", domain => "openpetfoodfacts.org", + }, + 'off-pro' => { + name => "Open Food Facts Pro", + mongodb => "off-pro", + domain => "pro.openfoodfacts.org", } }; diff --git a/lib/ProductOpener/Display.pm b/lib/ProductOpener/Display.pm index ec547eca02e99..898bdf9159188 100644 --- a/lib/ProductOpener/Display.pm +++ b/lib/ProductOpener/Display.pm @@ -7925,8 +7925,12 @@ JS } # If the product has a product_type and it is not the product_type of the server, redirect to the correct server + # unless we are in the pro platform - if ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + if ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { redirect_to_url($request_ref, 302, format_subdomain($subdomain, $product_ref->{product_type}) . product_url($product_ref)); } @@ -10614,16 +10618,25 @@ sub display_product_api ($request_ref) { $response{jqm} .= $html; } } - elsif ((defined $product_ref->{product_type}) and ($product_ref->{product_type} ne $options{product_type})) { + elsif ( (not $server_options{private_products}) + and (defined $product_ref->{product_type}) + and ($product_ref->{product_type} ne $options{product_type})) + { # If the product has a product_type and it is not the product_type of the server, # redirect to the correct server if the request includes a matching product_type parameter (or the "all" product type) + # If we are on the producers platform, don't redirect as we have only one server for all flavors my $requested_product_type = single_param("product_type"); if ( (defined $requested_product_type) and (($requested_product_type eq "all") or ($requested_product_type eq $product_ref->{product_type}))) { - redirect_to_url($request_ref, 302, + my $status_code = 302; + # If the method is POST, PUT, PATCH or DELETE, return a 307 status code + if ($request_ref->{api_method} =~ /^(POST|PUT|PATCH|DELETE)$/) { + $status_code = 307; + } + redirect_to_url($request_ref, $status_code, format_subdomain($subdomain, $product_ref->{product_type}) . "/" . $request_ref->{original_query_string}); } diff --git a/lib/ProductOpener/Products.pm b/lib/ProductOpener/Products.pm index 0e4e0f5a2e0b7..ccef4560ac403 100644 --- a/lib/ProductOpener/Products.pm +++ b/lib/ProductOpener/Products.pm @@ -505,7 +505,7 @@ The product id. sub product_id_for_owner ($ownerid, $code) { - if ((defined $server_options{private_products}) and ($server_options{private_products})) { + if ($server_options{private_products}) { if (defined $ownerid) { return $ownerid . "/" . $code; } @@ -561,8 +561,7 @@ The relative path for the product. sub product_path_from_id ($product_id) { - if ( (defined $server_options{private_products}) - and ($server_options{private_products}) + if ( ($server_options{private_products}) and ($product_id =~ /\//)) { return $` . "/" . split_code($'); @@ -596,7 +595,7 @@ sub product_path ($product_ref) { die("Argument of product_path() must be a reference to the product hash object, not a scalar: $product_ref\n"); } - if ((defined $server_options{private_products}) and ($server_options{private_products})) { + if ($server_options{private_products}) { return $product_ref->{owner} . "/" . split_code($product_ref->{code}); } else { @@ -642,7 +641,7 @@ sub product_exists ($product_id) { sub get_owner_id ($userid, $orgid, $ownerid) { - if ((defined $server_options{private_products}) and ($server_options{private_products})) { + if ($server_options{private_products}) { if (not defined $ownerid) { if (defined $orgid) { @@ -704,7 +703,7 @@ sub init_product ($userid, $orgid, $code, $countryid) { $product_ref->{server} = $server; } - if ((defined $server_options{private_products}) and ($server_options{private_products})) { + if ($server_options{private_products}) { my $ownerid = get_owner_id($userid, $orgid, $Owner_id); $product_ref->{owner} = $ownerid; @@ -1034,6 +1033,36 @@ sub compute_sort_keys ($product_ref) { return; } +=head2 get_server_for_product ( $product_ref ) + +Return the MongoDB database for the product: off, obf, opf, opff or off-pro + +If we are on the producers platform, we currently have only one server: off-pro + +=cut + +sub get_server_for_product ($product_ref) { + + my $server; + + # On the pro platform, we currently have only one server + if ($server_options{private_products}) { + $server = $mongodb; # off-pro + } + else { + # In case we need to move a product from OFF to OBF etc. + # we will have a old_product_type field + + $server + = $options{product_types_flavors}{$product_ref->{old_product_type} + || $product_ref->{product_type} + || $options{product_type}}; + + } + + return $server; +} + =head2 store_product ($user_id, $product_ref, $comment) Save changes of a product: @@ -1084,10 +1113,7 @@ sub store_product ($user_id, $product_ref, $comment) { # we will have a old_product_type field # Get the previous server and collection for the product - my $previous_server - = $options{product_types_flavors}{$product_ref->{old_product_type} - || $product_ref->{product_type} - || $options{product_type}}; + my $previous_server = get_server_for_product($product_ref); # We use the was_obsolete flag so that we can remove the product from its old collection # (either products or products_obsolete) if its obsolete status has changed @@ -1104,7 +1130,7 @@ sub store_product ($user_id, $product_ref, $comment) { } # Get the server and collection for the product that we will write - my $new_server = $options{product_types_flavors}{$product_ref->{product_type} || $options{product_type}}; + my $new_server = get_server_for_product($product_ref); my $new_products_collection = get_products_collection( {database => $options{other_servers}{$new_server}{mongodb}, obsolete => $product_ref->{obsolete}}); @@ -1699,7 +1725,7 @@ sub compute_completeness_and_missing_tags ($product_ref, $current_ref, $previous } # On the producers platform, keep track of which products have changes to be exported - if ((defined $server_options{private_products}) and ($server_options{private_products})) { + if ($server_options{private_products}) { if ( (defined $product_ref->{last_exported_t}) and ($product_ref->{last_exported_t} > $product_ref->{last_modified_t})) {