-
-
Notifications
You must be signed in to change notification settings - Fork 67
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: 617 - new "save packagings V3" feature #640
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -3,6 +3,7 @@ import 'package:openfoodfacts/model/Attribute.dart'; | |||||
import 'package:openfoodfacts/model/AttributeGroup.dart'; | ||||||
import 'package:openfoodfacts/model/KnowledgePanels.dart'; | ||||||
import 'package:openfoodfacts/model/ProductImage.dart'; | ||||||
import 'package:openfoodfacts/model/ProductPackaging.dart'; | ||||||
import 'package:openfoodfacts/utils/JsonHelper.dart'; | ||||||
import 'package:openfoodfacts/utils/LanguageHelper.dart'; | ||||||
import 'package:openfoodfacts/utils/ProductFields.dart'; | ||||||
|
@@ -311,8 +312,14 @@ class Product extends JsonObject { | |||||
includeIfNull: false) | ||||||
Map<OpenFoodFactsLanguage, List<String>>? labelsTagsInLanguages; | ||||||
|
||||||
// TODO: deprecated from 2022-12-16; remove when old enough | ||||||
@Deprecated('User packagingS instead') | ||||||
@JsonKey(name: 'packaging', includeIfNull: false) | ||||||
String? packaging; | ||||||
|
||||||
@JsonKey(name: 'packagings', includeIfNull: false) | ||||||
List<ProductPackaging>? packagings; | ||||||
|
||||||
@JsonKey(name: 'packaging_tags', includeIfNull: false) | ||||||
List<String>? packagingTags; | ||||||
@JsonKey( | ||||||
|
@@ -468,7 +475,8 @@ class Product extends JsonObject { | |||||
this.labels, | ||||||
this.labelsTags, | ||||||
this.labelsTagsInLanguages, | ||||||
this.packaging, | ||||||
// TODO: deprecated from 2022-12-16; remove when old enough | ||||||
@Deprecated('Use packagingS field instead') this.packaging, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Feel free to leave it with the capital S There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The square bracket syntax is unfortunately not detected in strings, only in |
||||||
this.packagingTags, | ||||||
this.miscTags, | ||||||
this.statesTags, | ||||||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import 'package:json_annotation/json_annotation.dart'; | ||
import 'package:openfoodfacts/model/LocalizedTag.dart'; | ||
import '../interface/JsonObject.dart'; | ||
|
||
part 'ProductPackaging.g.dart'; | ||
|
||
/// Packaging component for a product, e.g. recyclable bottle made of glass. | ||
@JsonSerializable() | ||
class ProductPackaging extends JsonObject { | ||
@JsonKey(includeIfNull: false) | ||
LocalizedTag? shape; | ||
|
||
@JsonKey(includeIfNull: false) | ||
LocalizedTag? material; | ||
|
||
@JsonKey(includeIfNull: false) | ||
LocalizedTag? recycling; | ||
|
||
@JsonKey( | ||
name: 'number_of_units', | ||
includeIfNull: false, | ||
fromJson: JsonObject.parseInt, | ||
) | ||
int? numberOfUnits; | ||
|
||
ProductPackaging(); | ||
|
||
factory ProductPackaging.fromJson(dynamic json) => | ||
_$ProductPackagingFromJson(json); | ||
|
||
@override | ||
Map<String, dynamic> toJson() => _$ProductPackagingToJson(this); | ||
|
||
Map<String, String> toServerData() => JsonObject.toDataStatic(toJson()); | ||
|
||
@override | ||
String toString() => toServerData().toString(); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,6 +6,7 @@ import 'dart:developer'; | |||||
|
||||||
import 'package:http/http.dart'; | ||||||
import 'package:openfoodfacts/interface/JsonObject.dart'; | ||||||
import 'package:openfoodfacts/model/ProductPackaging.dart'; | ||||||
import 'package:openfoodfacts/model/ProductResultV3.dart'; | ||||||
import 'package:openfoodfacts/model/KnowledgePanels.dart'; | ||||||
import 'package:openfoodfacts/model/LoginStatus.dart'; | ||||||
|
@@ -147,6 +148,48 @@ class OpenFoodAPIClient { | |||||
return Status.fromApiResponse(response.body); | ||||||
} | ||||||
|
||||||
/// Temporary: saves product packagings V3 style. | ||||||
/// | ||||||
/// For the moment that's the only field supported in WRITE by API V3. | ||||||
/// Long term target is of course more something like [saveProduct]. | ||||||
static Future<ProductResultV3> temporarySaveProductV3( | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Just a suggestion There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could make sense but in the long run I expect more fields to match V3 (e.g. one by month) : I'm not going to create a different method for each. |
||||||
final User user, | ||||||
final String barcode, { | ||||||
final List<ProductPackaging>? packagings, | ||||||
final QueryType? queryType, | ||||||
final OpenFoodFactsCountry? country, | ||||||
final OpenFoodFactsLanguage? language, | ||||||
}) async { | ||||||
final Map<String, dynamic> parameterMap = <String, dynamic>{}; | ||||||
parameterMap.addAll(user.toData()); | ||||||
if (packagings == null) { | ||||||
// For the moment it's the only purpose of this method: saving packagings. | ||||||
throw Exception('packagings cannot be null'); | ||||||
} | ||||||
parameterMap['product'] = {}; | ||||||
parameterMap['product']['packagings'] = packagings; | ||||||
if (language != null) { | ||||||
parameterMap['lc'] = language.offTag; | ||||||
parameterMap['tags_lc'] = language.offTag; | ||||||
} | ||||||
if (country != null) { | ||||||
parameterMap['cc'] = country.offTag; | ||||||
} | ||||||
|
||||||
var productUri = UriHelper.getPatchUri( | ||||||
path: '/api/v3/product/$barcode', | ||||||
queryType: queryType, | ||||||
); | ||||||
|
||||||
final Response response = await HttpHelper().doPatchRequest( | ||||||
productUri, | ||||||
parameterMap, | ||||||
user, | ||||||
queryType: queryType, | ||||||
); | ||||||
return ProductResultV3.fromJson(jsonDecode(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. | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,10 +29,10 @@ class HttpHelper { | |
static const String FROM = 'anonymous'; | ||
|
||
/// Adds user agent data to parameters, for statistics purpose | ||
static Map<String, String>? addUserAgentParameters( | ||
Map<String, String>? map, | ||
static Map<String, dynamic>? addUserAgentParameters( | ||
Map<String, dynamic>? map, | ||
) { | ||
map ??= <String, String>{}; | ||
map ??= <String, dynamic>{}; | ||
Comment on lines
+32
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why dynamic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With the new method parameterMap['product']['packagings'] = packagings; |
||
if (OpenFoodAPIConfiguration.userAgent?.name != null) { | ||
map['app_name'] = OpenFoodAPIConfiguration.userAgent!.name!; | ||
} | ||
|
@@ -70,9 +70,7 @@ class HttpHelper { | |
headers: _buildHeaders( | ||
user: user, | ||
isTestModeActive: | ||
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD | ||
? false | ||
: true, | ||
OpenFoodAPIConfiguration.getQueryType(queryType) != QueryType.PROD, | ||
), | ||
); | ||
|
||
|
@@ -105,16 +103,37 @@ class HttpHelper { | |
headers: _buildHeaders( | ||
user: user, | ||
isTestModeActive: | ||
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD | ||
? false | ||
: true, | ||
OpenFoodAPIConfiguration.getQueryType(queryType) != QueryType.PROD, | ||
addCredentialsToHeader: addCredentialsToHeader, | ||
), | ||
body: addUserAgentParameters(body), | ||
); | ||
return response; | ||
} | ||
|
||
static const String userInfoForTest = 'off:off'; | ||
|
||
/// Send a http PATCH request to the specified uri. | ||
/// | ||
/// The data / body of the request has to be provided as map. (key, value) | ||
/// The result of the request will be returned as string. | ||
Future<http.Response> doPatchRequest( | ||
final Uri uri, | ||
final Map<String, dynamic> body, | ||
final User? user, { | ||
final QueryType? queryType, | ||
}) async => | ||
http.patch( | ||
uri, | ||
headers: _buildHeaders( | ||
user: user, | ||
isTestModeActive: OpenFoodAPIConfiguration.getQueryType(queryType) != | ||
QueryType.PROD, | ||
addCredentialsToHeader: false, | ||
), | ||
body: jsonEncode(addUserAgentParameters(body)), | ||
); | ||
|
||
/// Send a multipart post request to the specified uri. | ||
/// The data / body of the request has to be provided as map. (key, value) | ||
/// The files to send have to be provided as map containing the source file uri. | ||
|
@@ -132,14 +151,13 @@ class HttpHelper { | |
_buildHeaders( | ||
user: user, | ||
isTestModeActive: | ||
OpenFoodAPIConfiguration.getQueryType(queryType) == QueryType.PROD | ||
? false | ||
: true, | ||
OpenFoodAPIConfiguration.getQueryType(queryType) != QueryType.PROD, | ||
) as Map<String, String>, | ||
); | ||
|
||
request.headers.addAll({'Content-Type': 'multipart/form-data'}); | ||
request.fields.addAll(addUserAgentParameters(body)!); | ||
addUserAgentParameters(body); | ||
request.fields.addAll(body); | ||
if (user != null) { | ||
request.fields.addAll(user.toData()); | ||
} | ||
|
@@ -192,7 +210,7 @@ class HttpHelper { | |
}); | ||
|
||
if (isTestModeActive && !addCredentialsToHeader) { | ||
var token = 'Basic ${base64Encode(utf8.encode('off:off'))}'; | ||
var token = 'Basic ${base64Encode(utf8.encode(userInfoForTest))}'; | ||
headers.addAll({'Authorization': token}); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.