2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

Driving the refactor tractor

- Separated get into getRequest and get
- Improved login error messages
This commit is contained in:
Oliver Walters 2021-04-20 10:32:01 +10:00
parent f5e1f25dd0
commit 8a6be4142a
2 changed files with 110 additions and 74 deletions

View File

@ -165,21 +165,27 @@ class InvenTreeAPI {
InvenTreeAPI._internal(); InvenTreeAPI._internal();
/**
* Connect to the remote InvenTree server:
*
* - Check that the InvenTree server exists
* - Request user token from the server
* - Request user roles from the server
*/
Future<bool> _connect(BuildContext context) async { Future<bool> _connect(BuildContext context) async {
/* Address is the base address for the InvenTree server,
* e.g. http://127.0.0.1:8000
*/
if (profile == null) return false; if (profile == null) return false;
var ctx = OneContext().context;
String address = profile.server.trim(); String address = profile.server.trim();
String username = profile.username.trim(); String username = profile.username.trim();
String password = profile.password.trim(); String password = profile.password.trim();
if (address.isEmpty || username.isEmpty || password.isEmpty) { if (address.isEmpty || username.isEmpty || password.isEmpty) {
showSnackIcon( showSnackIcon(
"Incomplete server details", "Incomplete profile details",
icon: FontAwesomeIcons.exclamationCircle, icon: FontAwesomeIcons.exclamationCircle,
success: false success: false
); );
@ -189,28 +195,36 @@ class InvenTreeAPI {
if (!address.endsWith('/')) { if (!address.endsWith('/')) {
address = address + '/'; address = address + '/';
} }
/* TODO: Better URL validation
// TODO - Better URL validation
/*
* - If not a valid URL, return error * - If not a valid URL, return error
* - If no port supplied, append a default port * - If no port supplied, append a default port
*/ */
_BASE_URL = address; _BASE_URL = address;
print("Connecting to ${apiUrl} -> ${username}:${password}"); print("Connecting to ${apiUrl} -> username=${username}");
// Request the /api/ endpoint - response is a json object HttpClientResponse response;
var response = await get(""); dynamic data;
response = await getResponse("");
// Null response means something went horribly wrong! // Null response means something went horribly wrong!
// Most likely, the server cannot be contacted
if (response == null) { if (response == null) {
// An error message has already been displayed!
return false; return false;
} }
if (response.statusCode != 200) {
showStatusCodeError(response.statusCode);
return false;
}
data = await responseToJson(response);
// We expect certain response from the server // We expect certain response from the server
if (!response.containsKey("server") || !response.containsKey("version") || !response.containsKey("instance")) { if (data == null || !data.containsKey("server") || !data.containsKey("version") || !data.containsKey("instance")) {
showServerError( showServerError(
"Missing Data", "Missing Data",
@ -221,16 +235,14 @@ class InvenTreeAPI {
} }
// Record server information // Record server information
_version = response["version"]; _version = data["version"];
instance = response['instance'] ?? ''; instance = data['instance'] ?? '';
// Default API version is 1 if not provided // Default API version is 1 if not provided
_apiVersion = response['apiVersion'] as int ?? 1; _apiVersion = data['apiVersion'] as int ?? 1;
if (_apiVersion < _minApiVersion) { if (_apiVersion < _minApiVersion) {
BuildContext ctx = OneContext().context;
String message = I18N.of(ctx).serverApiVersion + ": ${_apiVersion}"; String message = I18N.of(ctx).serverApiVersion + ": ${_apiVersion}";
message += "\n"; message += "\n";
@ -248,23 +260,43 @@ class InvenTreeAPI {
return false; return false;
} }
/**
* Request user token information from the server
* This is the stage that we check username:password credentials!
*/
// Clear the existing token value // Clear the existing token value
_token = ""; _token = "";
print("Requesting token from server"); print("Requesting token from server");
response = await get(_URL_GET_TOKEN); response = await getResponse(_URL_GET_TOKEN);
// A "null" response means that the request was unsuccessful
if (response == null) { if (response == null) {
showServerError( return false;
I18N.of(OneContext().context).tokenError, }
"Error requesting access token from server"
); if (response.statusCode != 200) {
switch (response.statusCode) {
case 401:
case 403:
showServerError(
I18N.of(ctx).serverAuthenticationError,
"Incorrect username:password combination"
);
break;
default:
showStatusCodeError(response.statusCode);
break;
}
return false; return false;
} }
if (!response.containsKey("token")) { data = await responseToJson(response);
if (data == null || !data.containsKey("token")) {
showServerError( showServerError(
I18N.of(OneContext().context).tokenMissing, I18N.of(OneContext().context).tokenMissing,
"Access token missing from response" "Access token missing from response"
@ -274,7 +306,7 @@ class InvenTreeAPI {
} }
// Return the received token // Return the received token
_token = response["token"]; _token = data["token"];
print("Received token - $_token"); print("Received token - $_token");
// Request user role information // Request user role information
@ -420,7 +452,7 @@ class InvenTreeAPI {
}); });
// Request could not be made // Request could not be made
if (request = null) { if (request == null) {
return null; return null;
} }
@ -474,7 +506,9 @@ class InvenTreeAPI {
return null; return null;
} }
return response; var responseData = await responseToJson(response);
return responseData;
} }
/* /*
@ -591,25 +625,9 @@ class InvenTreeAPI {
return null; return null;
} }
// Convert the body of the response to a JSON object var responseData = await responseToJson(response);
String responseData = await response.transform(utf8.decoder).join();
try { return responseData;
var data = json.decode(responseData);
return data;
} on FormatException {
print("JSON format exception!");
print("${responseData}");
showServerError(
"Format Exception",
"JSON data format exception:\n${responseData}"
);
return null;
}
} }
HttpClient createClient(bool allowBadCert) { HttpClient createClient(bool allowBadCert) {
@ -641,10 +659,11 @@ class InvenTreeAPI {
} }
/** /**
* Perform a HTTP GET request * Perform a HTTP GET request,
* Returns a json object (or null if did not complete) * and return the Response object
* (or null if the request fails)
*/ */
Future<dynamic> get(String url, {Map<String, String> params, int expectedStatusCode=200}) async { Future<HttpClientResponse> getResponse(String url, {Map<String, String> params}) async {
var _url = makeApiUrl(url); var _url = makeApiUrl(url);
print("GET: ${_url}"); print("GET: ${_url}");
@ -667,7 +686,7 @@ class InvenTreeAPI {
// Open a connection // Open a connection
HttpClientRequest request = await client.getUrl(Uri.parse(_url)) HttpClientRequest request = await client.getUrl(Uri.parse(_url))
.timeout(Duration(seconds: 10)) .timeout(Duration(seconds: 10))
.catchError((error) { .catchError((error) {
print("GET request returned error"); print("GET request returned error");
print("URL: ${_url}"); print("URL: ${_url}");
@ -700,11 +719,9 @@ class InvenTreeAPI {
request.headers.set(HttpHeaders.contentTypeHeader, 'application/json'); request.headers.set(HttpHeaders.contentTypeHeader, 'application/json');
request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader()); request.headers.set(HttpHeaders.authorizationHeader, _authorizationHeader());
print("Attempting connection");
HttpClientResponse response = await request.close() HttpClientResponse response = await request.close()
.timeout(Duration(seconds: 10)) .timeout(Duration(seconds: 10))
.catchError((error) { .catchError((error) {
print("GET request returned error"); print("GET request returned error");
print("URL: ${_url}"); print("URL: ${_url}");
print("Error: ${error.toString()}"); print("Error: ${error.toString()}");
@ -728,11 +745,46 @@ class InvenTreeAPI {
return null; return null;
}); });
print("got here"); return response;
}
dynamic responseToJson(HttpClientResponse response) async {
if (response == null) {
return null;
}
String body = await response.transform(utf8.decoder).join();
try {
var data = json.decode(body);
return data;
} on FormatException {
print("JSON format exception!");
print("${body}");
showServerError(
"Format Exception",
"JSON data format exception:\n${body}"
);
return null;
}
}
/**
* Perform a HTTP GET request
* Returns a json object (or null if did not complete)
*/
Future<dynamic> get(String url, {Map<String, String> params, int expectedStatusCode=200}) async {
var response = await getResponse(url, params: params);
// A null response means something has gone wrong... // A null response means something has gone wrong...
if (response == null) { if (response == null) {
print("null response from GET ${_url}"); print("null response from GET ${url}");
return null; return null;
} }
@ -742,25 +794,9 @@ class InvenTreeAPI {
return null; return null;
} }
// Convert the body of the response to a JSON object var data = await responseToJson(response);
String body = await response.transform(utf8.decoder).join();
try { return data;
var data = json.decode(body);
return data;
} on FormatException {
print("JSON format exception!");
print("${body}");
showServerError(
"Format Exception",
"JSON data format exception:\n${body}"
);
return null;
}
} }
Map<String, String> defaultHeaders() { Map<String, String> defaultHeaders() {

@ -1 +1 @@
Subproject commit 385c15b1e3275140c1b8a4e59de9513a6241dd9b Subproject commit 8c2bf9e993d5c618a0a7b5cb94d189b89d70cbe9