Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: #132 - new method OpenFoodAPIClient.addProductFields #436

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/openfoodfacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import 'package:openfoodfacts/model/TaxonomyLabel.dart';
import 'package:openfoodfacts/model/TaxonomyLanguage.dart';
import 'package:openfoodfacts/model/TaxonomyPackaging.dart';
import 'package:openfoodfacts/utils/AbstractQueryConfiguration.dart';
import 'package:openfoodfacts/utils/AddableProductFields.dart';
import 'package:openfoodfacts/utils/CountryHelper.dart';
import 'package:openfoodfacts/utils/ImageHelper.dart';
import 'package:openfoodfacts/utils/OcrField.dart';
Expand Down Expand Up @@ -131,6 +132,37 @@ class OpenFoodAPIClient {
return Status.fromApiResponse(response.body);
}

/// Add the given product to the database.
/// Returns a Status object as result.
static Future<Status> addProductFields(
final User user,
final String barcode,
final Map<AddableProductField, String> map, {
QueryType? queryType,
}) async {
if (map.isEmpty) {
throw Exception('Empty map');
monsieurtanuki marked this conversation as resolved.
Show resolved Hide resolved
}

final Map<String, String> parameterMap = <String, String>{};
parameterMap.addAll(user.toData());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By curiosity, why don't you call Map.from(user.toData)?

parameterMap['code'] = barcode;
for (final MapEntry<AddableProductField, String> entry in map.entries) {
parameterMap[entry.key.addableKey] = entry.value;
}

final Response response = await HttpHelper().doPostRequest(
UriHelper.getPostUri(
path: '/cgi/product_jqm2.pl',
queryType: queryType,
),
parameterMap,
user,
queryType: queryType,
);
return Status.fromApiResponse(response.body);
}

/// Send one image to the server.
/// The image will be added to the product specified in the SendImage
/// Returns a Status object as result.
Expand Down
17 changes: 17 additions & 0 deletions lib/utils/AddableProductFields.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// Fields of a [Product] that can be simply added.
enum AddableProductField {
BRANDS,
STORES,
COUNTRIES,
}

extension AddableProductFieldExtension on AddableProductField {
static const Map<AddableProductField, String> _KEYS = {
AddableProductField.BRANDS: 'add_brands',
AddableProductField.STORES: 'add_stores',
AddableProductField.COUNTRIES: 'add_countries',
};

/// Returns the key of the product field
String get addableKey => _KEYS[this] ?? '';
monsieurtanuki marked this conversation as resolved.
Show resolved Hide resolved
}
78 changes: 78 additions & 0 deletions test/api_addProductFields_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:openfoodfacts/utils/AddableProductFields.dart';
import 'package:openfoodfacts/utils/OpenFoodAPIConfiguration.dart';
import 'package:openfoodfacts/utils/QueryType.dart';
import 'package:test/test.dart';
import 'test_constants.dart';

/// Unit/Integration tests around OpenFoodAPIClient.addProductFields
void main() {
OpenFoodAPIConfiguration.globalQueryType = QueryType.TEST;

group('$OpenFoodAPIClient add product fields', () {
const String barcode = '0048151623426';
const String initialBrand = 'Golden Cookies';
const List<String> additionalBrands = <String>['djobi', 'djoba'];
const OpenFoodFactsLanguage language = OpenFoodFactsLanguage.ENGLISH;

test('add brand', () async {
late Status status;
late Product product;
late ProductResult productResult;
final ProductQueryConfiguration configurations =
ProductQueryConfiguration(
barcode,
language: language,
fields: [ProductField.ALL],
);

// brands from scratch
product = Product(
barcode: barcode,
lang: OpenFoodFactsLanguage.ENGLISH,
brands: initialBrand,
);
status = await OpenFoodAPIClient.saveProduct(
TestConstants.TEST_USER,
product,
);
expect(status.status, 1);
expect(status.statusVerbose, 'fields saved');

// cumulative list of brands
String expectedBrands = initialBrand;

productResult = await OpenFoodAPIClient.getProduct(
configurations,
user: TestConstants.TEST_USER,
);
expect(productResult.product, isNotNull);
expect(productResult.product!.brands, expectedBrands);

for (final String additionalBrand in additionalBrands) {
expectedBrands += ', $additionalBrand';

status = await OpenFoodAPIClient.addProductFields(
TestConstants.TEST_USER,
barcode,
<AddableProductField, String>{
AddableProductField.BRANDS: additionalBrand,
},
);
expect(status.status, 1);
expect(status.statusVerbose, 'fields saved');

productResult = await OpenFoodAPIClient.getProduct(
configurations,
user: TestConstants.TEST_USER,
);
expect(productResult.product, isNotNull);
expect(productResult.product!.brands, expectedBrands);
}
});
},
timeout: Timeout(
// some tests can be slow here
Duration(seconds: 90),
monsieurtanuki marked this conversation as resolved.
Show resolved Hide resolved
));
}