import 'dart:io'; import 'package:dio/dio.dart'; import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as path; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; import 'package:intl/intl.dart'; import 'package:mobdr/config/constant.dart'; import 'package:mobdr/main.dart'; import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/service/logger_util.dart'; class ApiProvider { final Dio _dio; ApiProvider() : _dio = Dio(); String connErr = 'Please check your internet connection and try again'; Future getCrud(url, body) async { print('url : ' + url.toString()); try { _dio.options.headers['content-Type'] = 'application/json'; _dio.options.headers['Accept'] = 'application/json'; _dio.options.headers['Cookie'] = "pguid=${SharedPrefs().guid}"; _dio.options.connectTimeout = Duration(seconds: 5); _dio.options.receiveTimeout = Duration(seconds: 4); if (body != null) { _dio.options.queryParameters = body; } return await _dio.get(url); } on DioException catch (e) { //print(e.toString()+' | '+url.toString()); if (e.type == DioExceptionType.badResponse) { int? statusCode = e.response!.statusCode; if (statusCode == STATUS_NOT_FOUND) { throw "Api not found"; } else if (statusCode == STATUS_INTERNAL_ERROR) { throw "Internal Server Error"; } else { throw e.error.toString(); } } else if (e.type == DioExceptionType.connectionTimeout) { throw e.message.toString(); } else if (e.type == DioExceptionType.cancel) { throw 'cancel'; } throw connErr; } } Future getConnect(url, apiToken) async { print('url : ' + url.toString()); try { _dio.options.headers['content-Type'] = 'application/x-www-form-urlencoded'; _dio.options.connectTimeout = Duration(seconds: 5); _dio.options.receiveTimeout = Duration(seconds: 4); return await _dio.post(url, cancelToken: apiToken); } on DioException catch (e) { //print(e.toString()+' | '+url.toString()); if (e.type == DioExceptionType.badResponse) { int? statusCode = e.response!.statusCode; if (statusCode == STATUS_NOT_FOUND) { throw "Api not found"; } else if (statusCode == STATUS_INTERNAL_ERROR) { throw "Internal Server Error"; } else { throw e.error.toString(); } } else if (e.type == DioExceptionType.connectionTimeout) { throw e.message.toString(); } else if (e.type == DioExceptionType.cancel) { throw 'cancel'; } throw connErr; } } Future postConnect(url, data, apiToken) async { print('url : ' + url.toString()); print('postData : ' + data.toString()); try { _dio.options.headers['content-Type'] = 'application/x-www-form-urlencoded'; _dio.options.connectTimeout = Duration(seconds: 5); _dio.options.receiveTimeout = Duration(seconds: 4); return await _dio.post(url, data: data, cancelToken: apiToken); } on DioException catch (e) { //print(e.toString()+' | '+url.toString()); if (e.type == DioExceptionType.badResponse) { int? statusCode = e.response!.statusCode; if (statusCode == STATUS_NOT_FOUND) { throw "Api not found"; } else if (statusCode == STATUS_INTERNAL_ERROR) { throw "Internal Server Error"; } else { throw e.error.toString(); } } else if (e.type == DioExceptionType.connectionTimeout) { throw e.message.toString(); } else if (e.type == DioExceptionType.cancel) { throw 'cancel'; } throw connErr; } } /// login function Future login( String userName, String pinCode, String securityCode) async { var body = { "application": "MobDR " + SharedPrefs().appVersion, "pin_code": md5.convert(utf8.encode(pinCode)), "security_code": securityCode, "langage": SharedPrefs().langage, "screenheight": SharedPrefs().screenHeight.truncate().toString(), "screenwidth": SharedPrefs().screenWidth.truncate().toString(), "browser_name": "Natif", "browser_version": "Flutter", "engine_name": SharedPrefs().systemName, "device_model": SharedPrefs().deviceModel, "device_type": SharedPrefs().deviceName, "device_vendor": SharedPrefs().systemName, "ismobile": 1, "engine_version": SharedPrefs().systemName, "os_name": SharedPrefs().systemName, "os_version": SharedPrefs().systemVersion, "fingerprint": SharedPrefs().fingerPrint }; Response response; try { response = await getCrud( ApiConstants.baseUrl + ApiConstants.mp4Endpoint + ApiConstants.restEndpoint + '/login/' + userName + '/guid', body); switch (response.data['autorisation']) { case 1: /// save user data SharedPrefs().id_utilisateur = response.data['id_utilisateur']; SharedPrefs().email = response.data['email']; SharedPrefs().expire = response.data['expire']; SharedPrefs().guid = response.data['guid']; SharedPrefs().langage = response.data['langage']; SharedPrefs().last_traduction = response.data['last_traduction']; SharedPrefs().login = response.data['login']; SharedPrefs().nom = response.data['nom']; SharedPrefs().prenom = response.data['prenom']; SharedPrefs().version = response.data['version']; SharedPrefs().photo = response.data['photo']; /// get image from url Response ReponseImg = await _dio.get(ApiConstants.baseUrl + response.data['photo'], options: Options( responseType: ResponseType.bytes, contentType: 'application/octet-stream', )); /// convert bytes to base64 string String base64Photo = base64.encode(ReponseImg.data); /// create box user objectbox.userBox.removeAll(); objectbox.addUSer( response.data['id_utilisateur'], response.data['login'], response.data['nom'], response.data['prenom'], base64Photo); return 'OK'; case -1: return 'Compte désactivé ...'; case -2: return 'SECURITY_CODE'; case -3: return 'Téléphone bloqué !'; case -4: return 'Code PIN incorrect !'; default: return "Une erreur inconnue s''est produite"; } } catch (ex) { return ex.toString(); // return ex.response!.data; } } Future guidActif() async { final url = '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/login/${SharedPrefs().login}/guidactif'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final response = await http.get(Uri.parse(url), headers: headers); if (response.statusCode == 200) { final jsonResponse = json.decode(response.body); if (jsonResponse.containsKey('general') && jsonResponse['general']['actif'] == true) { return true; } } return false; } /// Synchronize all informations about store, competitor, calendar Future SyncCalendar() async { DateTime now = DateTime.now(); DateTime end = now.add(Duration(days: 7)); String formattedStartDate = DateFormat('yyyyMMdd').format(now); String formattedEndDate = DateFormat('yyyyMMdd').format(end); try { final responseFutures = Future.wait([ getCrud( ApiConstants.baseUrl + ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/etablissement', null, ), getCrud( ApiConstants.baseUrl + ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/etablissement/concurrent', null, ), getCrud( ApiConstants.baseUrl + ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/visite/calendrier', { "id_utilisateur": SharedPrefs().id_utilisateur, "start": formattedStartDate, "end": formattedEndDate }, ), getCrud( ApiConstants.baseUrl + ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/visite/tag', null, ), getCrud( ApiConstants.baseUrl + ApiConstants.externalEndpoint + ApiConstants.restEndpoint + '/mobDR/visite/typologie', null), ]); final List> responses = await responseFutures.timeout(Duration(seconds: 30)); final etabResponse = responses[0]; final competitorResponse = responses[1]; final visitResponse = responses[2]; final visitTagResponse = responses[3]; final PhotoTypologyResponse = responses[4]; if (etabResponse.statusCode == STATUS_OK) { // remove all objects objectbox.etabBox.removeAll(); // fill box "Etabs" objectbox.addEtabs(etabResponse.data['boutiques']); } if (competitorResponse.statusCode == STATUS_OK) { // remove all objects objectbox.etabCompetitorBox.removeAll(); // fill box "Etabs" objectbox.addEtabCompetitors(competitorResponse.data['concurrents']); } if (visitResponse.statusCode == STATUS_OK) { /// fill box "visite" objectbox.syncVisits(visitResponse.data['events']); } if (visitTagResponse.statusCode == STATUS_OK) { // remove all objects objectbox.visitTagBox.removeAll(); /// fill box "visiteTag" objectbox.addVisitTags(visitTagResponse.data['tags']); } if (PhotoTypologyResponse.statusCode == STATUS_OK) { // remove all objects objectbox.PhotoTypologyBox.removeAll(); /// fill box "PhotoTypology" objectbox.addPhotoTypologies(PhotoTypologyResponse.data['typologies']); } if (etabResponse.statusCode == STATUS_OK && competitorResponse.statusCode == STATUS_OK && visitResponse.statusCode == STATUS_OK && visitTagResponse.statusCode == STATUS_OK && PhotoTypologyResponse.statusCode == STATUS_OK) { return 'OK'; } else { return etabResponse.statusMessage ?? competitorResponse.statusMessage ?? visitResponse.statusMessage ?? visitTagResponse.statusMessage ?? PhotoTypologyResponse.statusMessage ?? 'Unknown error'; } } catch (ex) { return ex.toString(); } } Future uploadPhotoServlet(int id_visite, String photoPath) async { try { final url = Uri.parse(SERVLET_API); final file = File(photoPath); final bytes = await file.readAsBytes(); final multipartRequest = http.MultipartRequest('POST', url) ..fields['id_visite'] = id_visite.toString() ..files.add(http.MultipartFile.fromBytes( 'photo', bytes, filename: path.basename(photoPath), contentType: MediaType('image', 'jpeg'), )); final headers = {'Cookie': "pguid=${SharedPrefs().guid};"}; multipartRequest.headers.addAll(headers); final response = await multipartRequest.send(); final responseString = await response.stream.bytesToString(); final jsonResponse = jsonDecode(responseString); final idPhotoString = jsonResponse[0]['id_photo']; final idPhoto = int.parse(idPhotoString); return idPhoto; } catch (e) { print('Error uploading photo: $e'); return -1; } } Future updatePhotoTypology( int id_visite, int id_photo_mp4, int id_photo_typologie) async { final url = '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/typo'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final params = { 'id_typologie': id_photo_typologie.toString(), }; final response = await http.put(Uri.parse(url), headers: headers, body: params); if (response.statusCode == 200) { return true; } else { return false; } } Future updatePhotoVisibility(int id_visite, int id_photo_mp4, int photo_principale, int photo_privee) async { final url = '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/visibilite'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final params = { 'principale': photo_principale.toString(), 'privee': photo_privee.toString(), }; final response = await http.put(Uri.parse(url), headers: headers, body: params); if (response.statusCode == 200) { return true; } else { return false; } } Future updatePhotoTags( int id_visite, int id_photo_mp4, String tags) async { final url = '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/tags'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final params = {'tags': tags}; final response = await http.put(Uri.parse(url), headers: headers, body: params); if (response.statusCode == 200) { return true; } else { return false; } } Future updatePhotoConpetitor( int id_visite, int id_photo_mp4, int id_concurrence_lien) async { final url = '${ApiConstants.baseUrl}${ApiConstants.mp4Endpoint}${ApiConstants.restEndpoint}/visite/$id_visite/photo/$id_photo_mp4/tri/concurrence'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final params = { 'id_concurrence_lien': id_concurrence_lien.toString(), }; final response = await http.put(Uri.parse(url), headers: headers, body: params); if (response.statusCode == 200) { return true; } else { return false; } } /// Synchronize log Future SyncLog() async { final url = '${ApiConstants.baseUrl}${ApiConstants.externalEndpoint}${ApiConstants.restEndpoint}/mobDR/log'; final headers = { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', 'Cookie': 'pguid=${SharedPrefs().guid};', }; final logs = await objectbox.getLogs().first; for (final log in logs) { final params = { 'date': log.dateEnFormat, 'libelle': '${log.module}.${log.libelle}', 'type': log.type, 'duree_ms': log.duree.toString(), }; final response = await http.post(Uri.parse(url), headers: headers, body: params); if (response.statusCode == 200) { // delete log objectbox.delLogById(log.id); } } return "OK"; } void close() { _dio.close(); } Future checkAppVersion() async { try { final response = await http .get(Uri.parse(DOMAIN_CHECK_VERSION + '/deploy/mobdr/version.json')); final data = jsonDecode(response.body); if (data.containsKey('latest_version')) { if (data['latest_version'] != SharedPrefs().appVersion) { LoggerUtil.logNStackInfo( 'A new version is available : ${data['latest_version']}'); // The versions differ return true; } } } catch (e) { print('Error verifying the version : $e'); } // If an error has occurred or if the versions are identical return false; } }