Skip to content

Commit

Permalink
refactor: merge the products and product images directories for OFF, …
Browse files Browse the repository at this point in the history
…OBF, OPF and OPFF (#10959)

In the last few weeks, we normalized product barcodes and deduplicated
products that existed in multiple flavors (Open Food Facts, Open Beauty
Facts, Open Product Facts and Open Pet Food Facts).

We are now going to merge the directories that contain product and
product revision data (the .sto files) and the product images. We will
keep separate MongoDB databases for each flavor.

This will:
- make it much easier to move products from one product type to another
- remove the possibility of having duplicate products on multiple
flavors
- make it much easier to have read and write APIs that can be used to
retrieve / update products of any type.

Deployment plan:
- stop OBF, OPF, OPFF for the duration of the migration (a couple of
hours)
- update OFF code
- move products and product images dirs from OBF, OPF, OPFF to the OFF
directory structure
- change the links to products and products of images on OBF, OPF, OPFF
to use the OFF dirs
- restart OBF, OPF, OPFF with the new code

In this PR:
- code updates to check product_type when reading / editing a product
for both the website and API. Redirect to the right flavor if the
product type is different than the one of the server the request was
made to.
- changed the product edit form to allow moderators to change the
product_type
- keep support for moderators to put "obf" etc. in the change code field
- tests for the above
- small refactor to put into Config.pm things that are the same for all
flavors and that are currently duplicated in Config_off.pm etc.

Will solve:
- #9221 
- #7539
- #1174
- #497
- #320
  • Loading branch information
stephanegigandet authored Nov 18, 2024
1 parent bbf092f commit c22734b
Show file tree
Hide file tree
Showing 66 changed files with 3,021 additions and 383 deletions.
54 changes: 42 additions & 12 deletions cgi/product_jqm_multilingual.pl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ =head1 DESCRIPTION
use ProductOpener::Packaging qw/:all/;
use ProductOpener::ForestFootprint qw/:all/;
use ProductOpener::Text qw/remove_tags_and_quote/;
use ProductOpener::API qw/get_initialized_response/;
use ProductOpener::API qw/get_initialized_response check_user_permission/;
use ProductOpener::APIProductWrite qw/skip_protected_field/;

use Apache2::RequestRec ();
Expand Down Expand Up @@ -114,6 +114,15 @@ =head1 DESCRIPTION
$product_ref = init_product($User_id, $Org_id, $code, $country);
$product_ref->{interface_version_created} = $interface_version;
}
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

if ((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);
}
}

# Process edit rules

Expand Down Expand Up @@ -219,25 +228,46 @@ =head1 DESCRIPTION
}
}

# 26/01/2017 - disallow barcode changes until we fix bug #677
if ($User{moderator} and (defined single_param('new_code'))) {
# Change code or product type

change_product_server_or_code($product_ref, single_param('new_code'), \@errors);
$code = $product_ref->{code};
if (defined single_param('new_code')) {

if ($#errors >= 0) {
$response{status} = 0;
$response{status_verbose} = 'new code is invalid';
if (check_user_permission($request_ref, $response_ref, "product_change_code")) {

my $data = encode_json(\%response);
push @errors, change_product_code($product_ref, single_param('new_code'));
$code = $product_ref->{code};
}
else {
push @errors, "No permission: product_change_code";
}
}

write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;
if ( (defined single_param("product_type"))
and ($product_ref->{product_type} ne single_param("product_type")))
{

exit(0);
if (check_user_permission($request_ref, $response_ref, "product_change_product_type")) {

push @errors, change_product_type($product_ref, single_param("product_type"));
}
else {
push @errors, "No permission: product_change_product_type";
}
}

# Display an error message and exit if we have a fatal error (no permission to change barcode or product type, or invalid barcode or product type)
if ($#errors >= 0) {
$response{status} = 0;
$response{status_verbose} = join(",", @errors);

my $data = encode_json(\%response);

write_cors_headers();
print header(-type => 'application/json', -charset => 'utf-8') . $data;

exit(0);
}

#my @app_fields = qw(product_name brands quantity);
my @app_fields
= qw(product_name generic_name quantity packaging brands categories labels origins manufacturing_places emb_codes link expiration_date purchase_places stores countries );
Expand Down
31 changes: 22 additions & 9 deletions cgi/product_multilingual.pl
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,15 @@ ($product_ref)
if (not defined $product_ref) {
display_error_and_exit($request_ref, sprintf(lang("no_product_for_barcode"), $code), 404);
}
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
# 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})) {
redirect_to_url($request_ref, 302,
format_subdomain($subdomain, $product_ref->{product_type}) . '/cgi/product.pl?code=' . $code);
}
}
}
}

Expand Down Expand Up @@ -399,11 +408,17 @@ ($product_ref)

exists $product_ref->{new_server} and delete $product_ref->{new_server};

# 26/01/2017 - disallow barcode changes until we fix bug #677
if ($User{moderator} and (defined single_param("new_code")) and (single_param("new_code") ne "")) {

change_product_server_or_code($product_ref, single_param("new_code"), \@errors);
$code = $product_ref->{code};
if ($request_ref->{admin} or $User{moderator}) {
if ((defined single_param("new_code")) and (single_param("new_code") ne "")) {
change_product_code($product_ref, single_param("new_code"));
$code = $product_ref->{code};
}
if ( (defined single_param("product_type"))
and (single_param("product_type") ne "")
and ($product_ref->{product_type} ne single_param("product_type")))
{
change_product_type($product_ref, single_param("product_type"));
}
}

my @param_fields = ();
Expand Down Expand Up @@ -848,14 +863,12 @@ ($product_ref, $field, $language, $request_ref)

my $label_new_code = $Lang{new_code}{$lc};

# 26/01/2017 - disallow barcode changes until we fix bug #677
if ($User{moderator}) {
}

$template_data_ref_display->{org_id} = $Org_id;
$template_data_ref_display->{label_new_code} = $label_new_code;
$template_data_ref_display->{owner_id} = $Owner_id;

$template_data_ref_display->{product_types} = $options{product_types};

# obsolete products: restrict to admin on public site
# authorize owners on producers platform
if ($User{moderator} or $Owner_id) {
Expand Down
13 changes: 7 additions & 6 deletions lib/ProductOpener/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ sub init_api_response ($request_ref) {
}

sub add_warning ($response_ref, $warning_ref) {
defined $response_ref->{warnings} or $response_ref->{warnings} = [];
push @{$response_ref->{warnings}}, $warning_ref;
return;
}
Expand All @@ -132,6 +133,7 @@ HTTP status code to return in the response, defaults to 400 bad request.
=cut

sub add_error ($response_ref, $error_ref, $status_code = 400) {
defined $response_ref->{errors} or $response_ref->{errors} = [];
push @{$response_ref->{errors}}, $error_ref;
$response_ref->{status_code} = $status_code;
return;
Expand Down Expand Up @@ -878,20 +880,19 @@ Reference to the response object.
Permission to check.
=head3 Return value
=head3 Return value $has_permission
1 if the user does not have the permission, 0 otherwise.
1 if the user has the permission, 0 otherwise.
=cut

sub check_user_permission ($request_ref, $response_ref, $permission) {

# We will return an error equal to 1 if the user does not have the permission
my $error = 0;
my $has_permission = 1;

# Check if the user has permission
if (not has_permission($request_ref, $permission)) {
$error = 1;
$has_permission = 0;
$log->error("check_user_permission - user does not have permission", {permission => $permission})
if $log->is_error();
add_error(
Expand All @@ -905,7 +906,7 @@ sub check_user_permission ($request_ref, $response_ref, $permission) {
);
}

return $error;
return $has_permission;
}

1;
28 changes: 27 additions & 1 deletion lib/ProductOpener/APIProductRead.pm
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,13 @@ use vars @EXPORT_OK;

use ProductOpener::Config qw/:all/;
use ProductOpener::Paths qw/%BASE_DIRS/;
use ProductOpener::Display qw/request_param single_param/;
use ProductOpener::Display qw/$subdomain redirect_to_url request_param single_param/;
use ProductOpener::Users qw/$Owner_id/;
use ProductOpener::Lang qw/$lc/;
use ProductOpener::Products qw/:all/;
use ProductOpener::Ingredients qw/flatten_sub_ingredients/;
use ProductOpener::API qw/add_error customize_response_for_product normalize_requested_code/;
use ProductOpener::URL qw(format_subdomain);

my $cc;

Expand Down Expand Up @@ -137,6 +138,31 @@ 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})) {

# 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)

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,
format_subdomain($subdomain, $product_ref->{product_type}) . $request_ref->{original_query_string});
}
else {
add_error(
$response_ref,
{
message => {id => "product_found_with_a_different_product_type"},
field => {id => "product_type", value => $product_ref->{product_type}},
impact => {id => "failure"},
},
404
);
$response_ref->{result} = {id => "product_found_with_a_different_product_type"};
}
}
else {
$response_ref->{result} = {id => "product_found"};

Expand Down
6 changes: 4 additions & 2 deletions lib/ProductOpener/APIProductRevert.pm
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,15 @@ sub revert_product_api ($request_ref) {
impact => {id => "failure"},
}
);
$error = 1;
$error++;
}
}

# Check that the user has permission (is an admin or a moderator, or we are on the producers platform)

$error += check_user_permission($request_ref, $response_ref, "product_revert");
if (not check_user_permission($request_ref, $response_ref, "product_revert")) {
$error++;
}

if (not $error) {

Expand Down
Loading

0 comments on commit c22734b

Please sign in to comment.