Skip to content

Commit

Permalink
chore: preparation of the 3.0.0 release (#809)
Browse files Browse the repository at this point in the history
* chore: preparation of the 3.0.0 release

Impacted files:
* `api_add_product_image_test.dart`: minor refactoring
* `api_get_product_test.dart`: minor refactoring
* `api_not_food_get_product_test.dart`: minor refactoring
* `configuration_test.dart`: minor refactoring
* `image_helper.dart`: methods `getProductImageRootUrl`, `getBarcodeSubPath` are moved to `UriProductHelper`; method `buildUrl` loses one parameter; method `buildUrl` renamed as `getLocalizedProductImageUrl`
* `open_food_api_client.dart`: minor refactoring
* `open_food_api_configuration.dart`: minor refactoring
* `product_helper.dart`: minor refactoring
* `README.md`: added migration instructions
* `uri_helper.dart`: now we use `domain` instead of `host` for `UriProductHelper`; methods `getProductImageRootUrl`, `getBarcodeSubPath` are moved from `ImageHelper`

* chore: additional fix around url field in product image

Impacted files:
* `api_json_to_from_test.dart`: minor change to make the test more relevant
* `json_helper.dart`: added field `url` in the to/fromJSON image conversion methods
* `product_helper.dart`: minor fix

* chore: Object instead of dynamic

Impacted file:
* `json_helper.dart`: `Object` instead of `dynamic`
  • Loading branch information
monsieurtanuki authored Sep 30, 2023
1 parent de8452a commit 2a4f7d2
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 92 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ This plugin also allows you to edit a product or upload a new one to Open Food F

## Migrating from 2.x.x to 3.x.x (breaking changes)

Starting with version 3.0.0, we now enforce all clients to provide a valid user agent.
- Starting with version 3.0.0, we now enforce all clients to provide a valid user agent.
For this, please ensure to set the SDK before using any other functionality:

```dart
Expand All @@ -32,6 +32,20 @@ OpenFoodAPIConfiguration.userAgent = UserAgent(
);
```

- `QueryType` has been deleted. Now, for API calls you have to provide a `UriProductHelper` parameter. By default it will point you to openfoodfacts/prod.

- For `RobotoffAPIClient.getRandomInsights` and `RobotoffAPIClient.getQuestions`, a list of countries instead of a single country as parameter.

- Use `OpenFoodFactsCountry.fromOffTag` instead of `CountryHelper.fromJson`.

- `OpenFoodAPIClient.getOrderedNutrients` now uses a `OpenFoodFactsCountry` parameter instead of a 2-letter country code.

- Methods `getProductImageRootUrl` and `getBarcodeSubPath` are moved to `UriProductHelper` from `ImageHelper`

- Method `buildUrl` renamed as `getLocalizedProductImageUrl` in `ImageHelper`

- Removal of deprecated code.

## Migrating from 1.x.x to 2.x.x (breaking changes)

- Now the only entry point is `import 'package:openfoodfacts/openfoodfacts.dart';`
Expand Down
2 changes: 1 addition & 1 deletion lib/src/open_food_api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1263,7 +1263,7 @@ class OpenFoodAPIClient {
if (filename == null) {
return null;
}
return '${ImageHelper.getProductImageRootUrl(barcode, root: uriHelper.imageUrlBase)}/$filename';
return '${uriHelper.getProductImageRootUrl(barcode)}/$filename';
}

/// Unselect a product image.
Expand Down
73 changes: 17 additions & 56 deletions lib/src/utils/image_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,38 @@ class ImageHelper {

/// Returns the [image] full url - for a specific [imageSize] if needed.
///
/// Returns null is [barcode] is null.
/// E.g. "https://static.openfoodfacts.org/images/products/359/671/046/2858/front_fr.4.100.jpg"
static String? buildUrl(
final String? barcode,
/// E.g. "https://images.openfoodfacts.org/images/products/359/671/046/2858/front_fr.4.100.jpg"
static String getLocalizedProductImageUrl(
final String barcode,
final ProductImage image, {
final ImageSize? imageSize,
final UriProductHelper uriHelper = uriHelperFoodProd,
final String? root,
}) =>
barcode == null
? null
: '${getProductImageRootUrl(
barcode,
uriHelper: uriHelper,
root: root,
)}'
'/'
'${getProductImageFilename(
image,
imageSize: imageSize,
)}';
'${uriHelper.getProductImageRootUrl(barcode)}'
'/'
'${getProductImageFilename(
image,
imageSize: imageSize,
)}';

/// Returns the [image] full url for an uploaded image.
/// Returns the [image] full url for an uploaded ("raw") image.
///
/// E.g. "https://static.openfoodfacts.org/images/products/359/671/046/2858/1.400.jpg"
/// E.g. "https://images.openfoodfacts.org/images/products/359/671/046/2858/1.400.jpg"
static String getUploadedImageUrl(
final String barcode,
final int imageId,
final ImageSize imageSize, {
final UriProductHelper uriHelper = uriHelperFoodProd,
}) =>
'${getProductImageRootUrl(barcode, uriHelper: uriHelper)}'
'${uriHelper.getProductImageRootUrl(barcode)}'
'/'
'${_getUploadedImageFilename(imageId, imageSize)}';
'${getUploadedImageFilename(imageId, imageSize)}';

/// Returns the [image] filename - for a specific [imageSize] if needed.
///
/// By default uses the own [image]'s size field.
/// E.g. "front_fr.4.100.jpg"
/// cf. https://github.com/openfoodfacts/smooth-app/issues/3065
static String getProductImageFilename(
final ProductImage image, {
final ImageSize? imageSize,
Expand All @@ -62,7 +55,9 @@ class ImageHelper {
'.jpg';

/// Returns the filename of an uploaded image.
static String _getUploadedImageFilename(
///
/// cf. https://github.com/openfoodfacts/smooth-app/issues/3065
static String getUploadedImageFilename(
final int imageId,
final ImageSize imageSize,
) {
Expand All @@ -80,38 +75,4 @@ class ImageHelper {
return '$imageId.jpg';
}
}

/// Returns the barcode sub-folder (without trailing '/').
///
/// For instance:
/// * `12345678` for barcode `12345678`
/// * `123/456/789` for barcode `123456789`
/// * `123/456/789/0` for barcode `1234567890`
/// * `123/456/789/0123` for barcode `1234567890123`
static String getBarcodeSubPath(final String barcode) {
if (barcode.length < 9) {
return barcode;
}
final String p1 = barcode.substring(0, 3);
final String p2 = barcode.substring(3, 6);
final String p3 = barcode.substring(6, 9);
if (barcode.length == 9) {
return '$p1/$p2/$p3';
}
final String p4 = barcode.substring(9);
return '$p1/$p2/$p3/$p4';
}

/// Returns the web folder of the product images (without trailing '/')
///
/// E.g. "https://static.openfoodfacts.org/images/products/359/671/046/2858"
static String getProductImageRootUrl(
final String barcode, {
final UriProductHelper uriHelper = uriHelperFoodProd,
String? root,
}) {
root ??= uriHelper.imageUrlBase;
final String separator = root.endsWith('/') ? '' : '/';
return '$root$separator${getBarcodeSubPath(barcode)}';
}
}
22 changes: 13 additions & 9 deletions lib/src/utils/json_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ class JsonHelper {
}
final int? width = JsonObject.parseInt(numberObject['w']);
final int? height = JsonObject.parseInt(numberObject['h']);
final String? url = numberObject['url'];

// TODO(monsieurtanuki): add field "url"?
var image = ProductImage(
field: field,
size: size,
Expand All @@ -154,6 +154,7 @@ class JsonHelper {
y2: y2,
width: width,
height: height,
url: url,
);
imageList.add(image);
}
Expand Down Expand Up @@ -191,45 +192,48 @@ class JsonHelper {
continue;
}
final Map<String, dynamic> item = <String, dynamic>{};
item['sizes'] = <String, Map<String, int>>{};
item['sizes'] = <String, Map<String, Object>>{};
bool first = true;
for (final ProductImage productImage in list) {
if (productImage.size == null) {
continue;
}
final Map<String, int> size = <String, int>{};
final Map<String, Object> size = <String, Object>{};
if (productImage.width != null) {
size['w'] = productImage.width!;
}
if (productImage.height != null) {
size['h'] = productImage.height!;
}
if (productImage.url != null) {
size['url'] = productImage.url!;
}
item['sizes']![productImage.size!.number] = size;
if (first) {
first = false;
if (productImage.rev != null) {
item['rev'] = productImage.rev.toString();
}
if (productImage.imgid != null) {
item['imgid'] = productImage.imgid;
item['imgid'] = productImage.imgid!;
}
if (productImage.angle != null) {
item['angle'] = productImage.angle!.degree.toString();
}
if (productImage.coordinatesImageSize != null) {
item['coordinates_image_size'] = productImage.coordinatesImageSize;
item['coordinates_image_size'] = productImage.coordinatesImageSize!;
}
if (productImage.x1 != null) {
item['x1'] = productImage.x1;
item['x1'] = productImage.x1!;
}
if (productImage.y1 != null) {
item['y1'] = productImage.y1;
item['y1'] = productImage.y1!;
}
if (productImage.x2 != null) {
item['x2'] = productImage.x2;
item['x2'] = productImage.x2!;
}
if (productImage.y2 != null) {
item['y2'] = productImage.y2;
item['y2'] = productImage.y2!;
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions lib/src/utils/open_food_api_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import 'uri_helper.dart';
/// E.g.
///
/// ```dart
/// OpenFoodAPIConfiguration.userAgent = UserAgent(
/// name: '<Name of your app>',
/// );
///
/// OpenFoodAPIConfiguration.globalLanguages = <OpenFoodFactsLanguage>[
/// OpenFoodFactsLanguage.ENGLISH,
/// ];
Expand Down Expand Up @@ -77,16 +81,14 @@ class OpenFoodAPIConfiguration {

/// Uri of the main requests to the backend (OFF).
const UriProductHelper uriHelperFoodProd = UriProductHelper(
host: 'world.openfoodfacts.org',
imageUrlBase: 'https://static.openfoodfacts.org/images/products/',
domain: 'openfoodfacts.org',
);

/// Uri of the test requests to the backend (OFF).
const UriProductHelper uriHelperFoodTest = UriProductHelper(
host: 'world.openfoodfacts.net',
domain: 'openfoodfacts.net',
userInfoForPatch: HttpHelper.userInfoForTest,
isTestMode: true,
imageUrlBase: 'https://static.openfoodfacts.net/images/products/',
);

/// Uri of the main requests to the backend (RobotOff).
Expand Down
8 changes: 6 additions & 2 deletions lib/src/utils/product_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ class ProductHelper {
return;
}

if (product.barcode == null) {
return;
}

for (ProductImage image in product.images!) {
image.url = ImageHelper.buildUrl(
product.barcode,
image.url = ImageHelper.getLocalizedProductImageUrl(
product.barcode!,
image,
uriHelper: uriHelper,
);
Expand Down
38 changes: 33 additions & 5 deletions lib/src/utils/uri_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,19 @@ class UriHelper {
/// [UriHelper] specific for products (e.g. off, obf, opf, opff).
class UriProductHelper extends UriHelper {
const UriProductHelper({
required super.host,
required this.domain,
super.scheme = 'https',
super.isTestMode = false,
this.userInfoForPatch,
required this.imageUrlBase,
super.defaultAddUserAgentParameters = true,
});
}) : super(host: 'world.$domain');

final String? userInfoForPatch;

/// Url base for images: needs to match more or less scheme and host.
final String imageUrlBase;
final String domain;

/// Returns the product images folder (without trailing '/').
String getImageUrlBase() => '$scheme://images.$domain/images/products';

Uri getPatchUri({
required final String path,
Expand All @@ -121,4 +122,31 @@ class UriProductHelper extends UriHelper {
addUserAgentParameters: false,
userInfo: userInfoForPatch,
);

/// Returns the web folder of the product images (without trailing '/')
///
/// E.g. "https://images.openfoodfacts.org/images/products/359/671/046/2858"
String getProductImageRootUrl(final String barcode) =>
'${getImageUrlBase()}/${getBarcodeSubPath(barcode)}';

/// Returns the barcode sub-folder (without trailing '/').
///
/// For instance:
/// * `12345678` for barcode `12345678`
/// * `123/456/789` for barcode `123456789`
/// * `123/456/789/0` for barcode `1234567890`
/// * `123/456/789/0123` for barcode `1234567890123`
static String getBarcodeSubPath(final String barcode) {
if (barcode.length < 9) {
return barcode;
}
final String p1 = barcode.substring(0, 3);
final String p2 = barcode.substring(3, 6);
final String p3 = barcode.substring(6, 9);
if (barcode.length == 9) {
return '$p1/$p2/$p3';
}
final String p4 = barcode.substring(9);
return '$p1/$p2/$p3/$p4';
}
}
3 changes: 1 addition & 2 deletions test/api_add_product_image_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,8 @@ void main() {
final String? imgid = await getImgid(barcode, imageField, language);
expect(imgid, isNotNull);

final String productImageRootUrl = ImageHelper.getProductImageRootUrl(
final String productImageRootUrl = uriHelper.getProductImageRootUrl(
barcode,
root: uriHelper.imageUrlBase,
);
final String uploadedImageUrl = '$productImageRootUrl/$imgid.jpg';
final List<int> uploadedSize = await getJpegUrlSize(uploadedImageUrl);
Expand Down
6 changes: 3 additions & 3 deletions test/api_get_product_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ void main() {
image.size == ImageSize.DISPLAY &&
image.language == OpenFoodFactsLanguage.GERMAN)
.url,
'https://static.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');
'https://images.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');

//Get product without setting ProductField
configurations = ProductQueryConfiguration(
Expand Down Expand Up @@ -779,7 +779,7 @@ void main() {
image.size == ImageSize.DISPLAY &&
image.language == OpenFoodFactsLanguage.GERMAN)
.url,
'https://static.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');
'https://images.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');

//Get product without setting OpenFoodFactsLanguage
configurations = ProductQueryConfiguration(
Expand Down Expand Up @@ -853,7 +853,7 @@ void main() {
image.size == ImageSize.DISPLAY &&
image.language == OpenFoodFactsLanguage.GERMAN)
.url,
'https://static.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');
'https://images.openfoodfacts.org/images/products/500/011/254/8167/ingredients_de.7.400.jpg');

final Set<ProductImprovement> improvements =
result.product!.getProductImprovements();
Expand Down
2 changes: 1 addition & 1 deletion test/api_json_to_from_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void main() {
await OpenFoodAPIClient.getProductV3(
ProductQueryConfiguration(
BARCODE_DANISH_BUTTER_COOKIES,
fields: [ProductField.IMAGES],
fields: [ProductField.IMAGES, ProductField.BARCODE],
version: ProductQueryVersion.v3,
),
);
Expand Down
9 changes: 3 additions & 6 deletions test/api_not_food_get_product_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@ void main() {
OpenFoodAPIConfiguration.globalUser = TestConstants.PROD_USER;

const UriProductHelper uriHelperBeautyProd = UriProductHelper(
host: 'world.openbeautyfacts.org',
imageUrlBase: 'https://static.openbeautyfacts.org/images/products/',
domain: 'openbeautyfacts.org',
);
const UriProductHelper uriHelperProductsProd = UriProductHelper(
host: 'world.openproductsfacts.org',
imageUrlBase: 'https://static.openproductsfacts.org/images/products/',
domain: 'openproductsfacts.org',
);
const UriProductHelper uriHelperPetFoodProd = UriProductHelper(
host: 'world.openpetfoodfacts.org',
imageUrlBase: 'https://static.openpetfoodfacts.org/images/products/',
domain: 'openpetfoodfacts.org',
);

const String beautyBarcode = '4056489234692';
Expand Down
Loading

0 comments on commit 2a4f7d2

Please sign in to comment.