diff --git a/assets/release_notes.md b/assets/release_notes.md index 96ad4e15..b98744e2 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,6 +1,11 @@ ## InvenTree App Release Notes --- +### 0.4.3 - August 2021 +--- + +- Multiple bug fixes, mostly related to API calls + ### 0.4.2 - August 2021 --- diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh index b5fb2e5b..7205b3af 100644 --- a/ios/Flutter/flutter_export_environment.sh +++ b/ios/Flutter/flutter_export_environment.sh @@ -6,8 +6,8 @@ export "COCOAPODS_PARALLEL_CODE_SIGN=true" export "FLUTTER_TARGET=lib\main.dart" export "FLUTTER_BUILD_DIR=build" export "SYMROOT=${SOURCE_ROOT}/../build\ios" -export "FLUTTER_BUILD_NAME=0.4.2" -export "FLUTTER_BUILD_NUMBER=24" +export "FLUTTER_BUILD_NAME=0.4.3" +export "FLUTTER_BUILD_NUMBER=25" export "DART_OBFUSCATION=false" export "TRACK_WIDGET_CREATION=false" export "TREE_SHAKE_ICONS=false" diff --git a/lib/api.dart b/lib/api.dart index 0f94c3ff..f47feccb 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -23,7 +23,7 @@ import 'package:inventree/widget/snacks.dart'; */ class APIResponse { - APIResponse({this.url = "", this.method = "", this.statusCode = -1, this.data = const {}}); + APIResponse({this.url = "", this.method = "", this.statusCode = -1, this.error = "", this.data = const {}}); int statusCode = -1; @@ -31,6 +31,10 @@ class APIResponse { String method = ""; + String error = ""; + + String errorDetail = ""; + dynamic data = {}; // Request is "valid" if a statusCode was returned @@ -430,9 +434,13 @@ class InvenTreeAPI { return true; } - List perms = List.from(roles[role]); - - return perms.contains(permission); + try { + List perms = List.from(roles[role]); + return perms.contains(permission); + } catch (error, stackTrace) { + sentryReportError(error, stackTrace); + return true; + } } @@ -450,6 +458,7 @@ class InvenTreeAPI { return new APIResponse( url: url, method: 'PATCH', + error: "HttpClientRequest is null" ); } @@ -487,6 +496,9 @@ class InvenTreeAPI { if (response.statusCode >= 500) { // Server error if (response.statusCode >= 500) { + + var data = await response.stream.bytesToString(); + sentryReportMessage( "Server error on file upload", context: { @@ -494,6 +506,7 @@ class InvenTreeAPI { "statusCode": "${response.statusCode}", "response": response.toString(), "request": request.fields.toString(), + "data": data, } ); } @@ -667,34 +680,43 @@ class InvenTreeAPI { } else { response.data = await responseToJson(_response) ?? {}; - // Expected status code not returned - if ((statusCode != null) && (statusCode != _response.statusCode)) { - showStatusCodeError(_response.statusCode); - } + if (statusCode != null) { - // Report any server errors - if (_response.statusCode >= 500) { - sentryReportMessage( - "Server error", - context: { - "url": request.uri.toString(), - "method": request.method, - "statusCode": _response.statusCode.toString(), - "requestHeaders": request.headers.toString(), - "responseHeaders": _response.headers.toString(), - "responseData": response.data.toString(), - } - ); + // Expected status code not returned + if (statusCode != _response.statusCode) { + showStatusCodeError(_response.statusCode); + } + + // Report any server errors + if (_response.statusCode >= 500) { + sentryReportMessage( + "Server error", + context: { + "url": request.uri.toString(), + "method": request.method, + "statusCode": _response.statusCode.toString(), + "requestHeaders": request.headers.toString(), + "responseHeaders": _response.headers.toString(), + "responseData": response.data.toString(), + } + ); + } } } } on SocketException catch (error) { showServerError(L10().connectionRefused, error.toString()); + response.error = "SocketException"; + response.errorDetail = error.toString(); + } on TimeoutException { showTimeoutError(); + response.error = "TimeoutException"; } catch (error, stackTrace) { showServerError(L10().serverError, error.toString()); sentryReportError(error, stackTrace); + response.error = "UnknownError"; + response.errorDetail = error.toString(); } return response; @@ -754,6 +776,7 @@ class InvenTreeAPI { return new APIResponse( url: url, method: 'GET', + error: "HttpClientRequest is null", ); } diff --git a/lib/barcode.dart b/lib/barcode.dart index 99891a99..3fb7bf96 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -114,6 +114,8 @@ class BarcodeHandler { "url": url, "statusCode": response.statusCode.toString(), "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, } ); } else if (response.data.containsKey('error')) { diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index 0a893f88..5c9f8f95 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -162,6 +162,8 @@ class InvenTreeModel { "statusCode": response.statusCode.toString(), "data": response.data?.toString() ?? "null", "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, } ); @@ -230,7 +232,9 @@ class InvenTreeModel { "url": url, "statusCode": response.statusCode.toString(), "data": response.data?.toString() ?? "null", - "valid": response.isValid().toString() + "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, } ); @@ -270,6 +274,8 @@ class InvenTreeModel { "statusCode": response.statusCode.toString(), "data": response.data?.toString() ?? "null", "valid": response.isValid().toString(), + "error": response.error, + "errorDetail": response.errorDetail, } ); diff --git a/lib/l10n b/lib/l10n index dd16aa78..c19a9d9a 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit dd16aa783769f261d73cb42ea70a831ddde04086 +Subproject commit c19a9d9af449f6a36df780c69cf1bd2bb087c252 diff --git a/lib/widget/part_image_widget.dart b/lib/widget/part_image_widget.dart index 6ac18f69..d1819cc1 100644 --- a/lib/widget/part_image_widget.dart +++ b/lib/widget/part_image_widget.dart @@ -10,6 +10,9 @@ import 'package:inventree/api.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:inventree/inventree/part.dart'; import 'package:inventree/widget/refreshable_state.dart'; +import 'package:inventree/widget/snacks.dart'; + +import '../l10.dart'; class PartImageWidget extends StatefulWidget { @@ -43,7 +46,11 @@ class _PartImageState extends RefreshableState { if (pickedImage != null) { File? img = File(pickedImage.path); - await part.uploadImage(img); + final result = await part.uploadImage(img); + + if (!result) { + showSnackIcon(L10().uploadFailed, success: false); + } refresh(); } @@ -58,7 +65,11 @@ class _PartImageState extends RefreshableState { if (pickedImage != null) { File? img = File(pickedImage.path); - await part.uploadImage(img); + final result = await part.uploadImage(img); + + if (!result) { + showSnackIcon(L10().uploadFailed, success: false); + } refresh(); } diff --git a/pubspec.yaml b/pubspec.yaml index 18277849..7dba451c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,7 +7,7 @@ description: InvenTree stock management # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 0.4.2+24 +version: 0.4.3+25 environment: sdk: ">=2.12.0 <3.0.0"