v1.0.0 outsourced from aitrainer_app

This commit is contained in:
Tibor Bossanyi (Freelancer)
2023-01-28 12:53:16 +01:00
commit ca96abf8c0
87 changed files with 7189 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
import 'dart:convert';
import 'dart:io';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:workouttest_util/util/common.dart';
import 'package:workouttest_util/util/not_found_exception.dart';
import 'package:flutter/services.dart';
import 'package:workouttest_util/model/cache.dart';
class APIClient with Common, Logging {
static final APIClient _singleton = APIClient._internal();
late bool cert;
factory APIClient() {
return _singleton;
}
APIClient._internal() {
cert = false;
}
dynamic authenticateUser(String email, String password) async {
var url = Cache().getBaseUrl() + "authenticate";
try {
ByteData data = await rootBundle.load('asset/data/aitrainer_server.crt.pem');
SecurityContext context = SecurityContext.defaultContext;
if (cert == false) {
print("Set CERT $cert");
context.setTrustedCertificatesBytes(data.buffer.asUint8List(), password: "[xxxx]");
cert = true;
}
HttpClient client = new HttpClient(); //context: context Todo provide the right certificate
client.badCertificateCallback = ((X509Certificate cert, String host, int port) {
print("Host: $host Port: $port");
return true;
});
var uri = Uri.parse(url);
final HttpClientRequest request = await client.postUrl(uri);
request.headers.set('Content-Type', 'application/json');
request.headers.set('Authorization', '1');
final body = '{"username":"$email", "password":"$password"}';
request.write(body);
HttpClientResponse result = await request.close();
client.close();
if (result.statusCode != 200) {
trace("authentication response: ${result.statusCode} with URL: $url");
throw Exception("Authentication error: ${result.statusCode}");
}
return jsonDecode(await result.transform(utf8.decoder).join());
} catch (exception) {
print(exception.toString());
try {
await Sentry.captureException(exception);
} on Exception catch (e) {
print(e);
}
throw Exception("Network error, try again later!");
}
}
Future<String> post(String endPoint, String body) async {
final url = Cache().getBaseUrl() + endPoint;
trace(" ------------ http/post body $body - url: $url ");
try {
String authToken = Cache().getAuthToken();
if (authToken.length == 0) {
var responseJson = await this.authenticateUser(Cache.username, Cache.password);
authToken = responseJson['token'];
Cache().authToken = authToken;
}
var uri = Uri.parse(url);
HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
final HttpClientRequest request = await client.postUrl(uri);
request.headers.contentType = new ContentType("application", "json", charset: "utf-8");
request.headers.set('Authorization', 'Bearer $authToken');
//request.contentLength = body.length;
request.write(body);
HttpClientResponse result = await request.close();
client.close();
trace(" ------------post response code: " + result.statusCode.toString());
if (result.statusCode == 200) {
return await result.transform(utf8.decoder).join();
} else if (result.statusCode == 404) {
throw NotFoundException(message: "Not Found");
} else {
throw Exception("Network Error, please try again later");
}
} on NotFoundException catch(e) {
throw NotFoundException(message: "Not Found");
} on Exception catch (e) {
print("Post Exception: $e");
await Sentry.captureException(e);
throw Exception("Network Error, please try again later");
}
}
Future<String> get(String endPoint, String param) async {
final url = Cache().getBaseUrl() + endPoint + param;
try {
trace("-------- API get " + url);
String authToken = Cache().getAuthToken();
if (authToken.length == 0) {
var responseJson = await this.authenticateUser(Cache.username, Cache.password);
authToken = responseJson['token'];
Cache().authToken = authToken;
}
var uri = Uri.parse(url);
HttpClient client = new HttpClient();
client.badCertificateCallback = ((X509Certificate cert, String host, int port) => true);
final HttpClientRequest request = await client.getUrl(uri);
request.headers.set('Content-Type', 'application/json');
request.headers.set('Authorization', 'Bearer $authToken');
HttpClientResponse result = await request.close();
client.close();
trace(" ------------get response code: " + result.statusCode.toString());
if (result.statusCode == 200) {
return await result.transform(utf8.decoder).join();
} else if (result.statusCode == 404) {
throw NotFoundException(message: "Not Found");
} else {
throw Exception("Network Error, please try again later");
}
} on NotFoundException catch(e) {
throw NotFoundException(message: "Not Found");
} on Exception catch (e) {
print("Post Exception: $e");
await Sentry.captureException(e);
throw Exception("Network Error, please try again later");
}
}
}
@@ -0,0 +1,47 @@
import 'package:workouttest_util/model/customer_exercise_device.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:workouttest_util/util/not_found_exception.dart';
import 'dart:convert';
import 'api.dart';
class CustomerExerciseDeviceApi with Logging {
final APIClient _client = APIClient();
Future<List<CustomerExerciseDevice>> getDevices(int customerId) async {
List<CustomerExerciseDevice> devices = [];
try {
log(" --- get customer_exercise_devices: ");
final body = await _client.get("customer_exercise_device/customer/" + customerId.toString(), "");
final Iterable json = jsonDecode(body);
devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
} on NotFoundException catch (_) {
log("No devices found");
devices = [];
}
return devices;
}
Future<CustomerExerciseDevice> addDevice(CustomerExerciseDevice device) async {
CustomerExerciseDevice savedDevice;
try {
final String body = JsonEncoder().convert(device.toJson());
log(" --- add customer_exercise_device: " + body);
final String responseBody = await _client.post("customer_exercise_device", body);
savedDevice = CustomerExerciseDevice.fromJson(jsonDecode(responseBody));
} on Exception catch (e) {
throw new Exception(e.toString());
}
return savedDevice;
}
Future<void> removeDevice(int id) async {
try {
log(" --- delete customer_exercise_device: " + id.toString());
await _client.post("customer_exercise_device/delete/" + id.toString(), "");
} on Exception catch (e) {
throw new Exception(e.toString());
}
return;
}
}
+240
View File
@@ -0,0 +1,240 @@
import 'dart:collection';
import 'dart:convert';
import 'package:workouttest_util/model/customer.dart';
import 'package:workouttest_util/model/customer_property.dart';
import 'package:workouttest_util/model/property.dart';
import 'package:workouttest_util/model/user.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:workouttest_util/util/not_found_exception.dart';
class CustomerApi with Logging {
final APIClient _client = APIClient();
Future<List<Customer>> getRealCustomers(String param) async {
final body = await _client.get("customers/", param);
final Iterable json = jsonDecode(body);
final List<Customer> customers = json.map((customer) => Customer.fromJson(customer)).toList();
return customers;
}
Future<void> saveCustomer(Customer customer) async {
customer.dateChange = DateTime.now();
String body = JsonEncoder().convert(customer.toJson());
log(" ===== saving customer id: " + customer.customerId.toString() + ":" + body);
await _client.post("customers/" + customer.customerId.toString(), body);
}
Future<void> updateFirebaseUid(int customerId, String uid) async {
log(" ===== update Firebase uid : " + customerId.toString() + ": " + uid);
await _client.post("customers/update_firebase_uid/" + customerId.toString(), uid);
}
Future<void> deactivateCustomer(int customerId) async {
log(" ===== deactivate : $customerId");
await _client.post("customers/deactivate/$customerId", "");
}
Future<void> addCustomer(Customer customer) async {
customer.dateAdd = DateTime.now();
customer.dateChange = DateTime.now();
String body = JsonEncoder().convert(customer.toJson());
log(" ===== add new customer: " + body);
await _client.post("customers", body);
}
Future<void> addUser(User user) async {
String body = JsonEncoder().convert(user.toJson());
log(" ===== add new user: " + body);
final String responseBody = await _client.post("registration", body);
Customer customer;
try {
int? status = jsonDecode(responseBody)['status'];
if (status != null) {
String error = jsonDecode(responseBody)['error'];
throw new Exception(error);
} else {
customer = Customer.fromJson(jsonDecode(responseBody));
await Cache().afterRegistration(customer);
}
} on FormatException {
if (responseBody == "Customer exists") {
throw WorkoutTestException(code: WorkoutTestException.CUSTOMER_EXISTS, message: responseBody);
}
throw new Exception(responseBody);
}
}
Future<void> getUser(User user) async {
String body = JsonEncoder().convert(user.toJson());
log(" ===== login the user: " + body);
final String responseBody = await _client.post("login", body);
Customer customer;
try {
customer = Customer.fromJson(jsonDecode(responseBody));
await Cache().afterLogin(customer);
} on FormatException {
throw new Exception(responseBody);
}
}
Future<void> getUserByEmail(String email) async {
log(" ===== User getByEmail : " + email);
final String responseBody = await _client.get("customers/find_by_email/" + email, "");
Customer customer;
try {
customer = Customer.fromJson(jsonDecode(responseBody));
if (customer.firebaseUid == null) {
await this.updateFirebaseUid(customer.customerId!, Cache().firebaseUid!);
}
Cache().userLoggedIn = customer;
final List<CustomerProperty>? properties = await this.getActualProperties(customer.customerId!);
if (properties != null) {
this.initProperties(properties);
}
} on FormatException {
throw new Exception(responseBody);
}
}
Future<void> getCustomer(int customerId) async {
String body = "";
log(" ===== get the customer by id: " + customerId.toString());
try {
final String responseBody = await _client.get("customers/" + customerId.toString(), body);
Customer customer = Customer.fromJson(jsonDecode(responseBody));
log(" --- Customer: " + customer.toJson().toString());
Cache().userLoggedIn = customer;
final List<CustomerProperty>? properties = await this.getActualProperties(customerId);
//log(" ---- Props: " + properties.toJson().toString());
//await Cache().initCustomer(customerId);
if (properties != null) {
this.initProperties(properties);
}
} on Exception catch (exception) {
log("Exception: " + exception.toString());
log(" === go to registration ");
Cache().logout();
Cache().startPage = "registration";
}
}
void initProperties(final List<CustomerProperty>? customerProperties) {
List<Property>? properties = Cache().getProperties();
Customer customer = Cache().userLoggedIn!;
customer.properties = LinkedHashMap<String, CustomerProperty>();
if (properties != null) {
// reset Properties
properties.forEach((property) {
CustomerProperty customerProperty =
CustomerProperty(propertyId: property.propertyId, customerId: customer.customerId!, dateAdd: DateTime.now(), propertyValue: 0);
customer.properties[property.propertyName] = customerProperty;
});
customerProperties!.forEach((customerProperty) {
properties.forEach((property) {
if (customerProperty.propertyId == property.propertyId) {
customer.properties[property.propertyName] = customerProperty;
}
});
});
}
}
Future<Customer> getTrainee(int customerId) async {
String body = "";
Customer customer;
log(" ===== get Trainee customer by id: " + customerId.toString());
try {
final String responseBody = await _client.get("customers/" + customerId.toString(), body);
customer = Customer.fromJson(jsonDecode(responseBody));
log(" --- Trainee: " + customer.toJson().toString());
} catch (exception) {
log("Exception: " + exception.toString());
throw Exception(exception);
}
return customer;
}
Future<List<Customer>> getTrainees(int trainerId) async {
List<Customer> trainees = [];
log("Get trainees list");
try {
String body = "";
final String responseBody = await _client.get("customers/trainees/" + trainerId.toString(), body);
final Iterable json = jsonDecode(responseBody);
trainees = json.map((customer) => Customer.fromJson(customer)).toList();
} catch (exception) {
log("Exception: " + exception.toString());
throw Exception(exception);
}
return trainees;
}
Future<List<CustomerProperty>> getAllProperties(int customerId) async {
final body = await _client.get("customer_property/", customerId.toString());
final Iterable json = jsonDecode(body);
final List<CustomerProperty> properties = json.map((property) => CustomerProperty.fromJson(property)).toList();
return properties;
}
Future<List<CustomerProperty>?> getActualProperties(int customerId) async {
List<CustomerProperty>? properties;
try {
final body = await _client.get("customer_property/last/", customerId.toString());
final Iterable json = jsonDecode(body);
properties = json.map((property) => CustomerProperty.fromJson(property)).toList();
} on Exception catch (ex) {
log(ex.toString());
}
return properties;
}
Future<CustomerProperty> addProperty(CustomerProperty property) async {
String body = JsonEncoder().convert(property.toJson());
log(" ===== add new customer property: " + body);
CustomerProperty customerProperty;
String? responseBody;
try {
responseBody = await _client.post("customer_property", body);
log(" responseBody: " + responseBody);
int? status = jsonDecode(responseBody)['status'];
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
} else {
customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody));
}
} on FormatException {
throw new Exception(responseBody);
} on Exception catch (e) {
throw new Exception(e);
}
return customerProperty;
}
Future<CustomerProperty> updateProperty(CustomerProperty property) async {
String body = JsonEncoder().convert(property.toJson());
CustomerProperty? customerProperty;
log(" ===== update customer property: " + body);
String? responseBody;
try {
responseBody = await _client.post("customer_property/update/" + property.customerPropertyId.toString(), body);
log(" responseBody: " + responseBody);
int? status = jsonDecode(responseBody)['status'];
if (status != null) {
throw new Exception(jsonDecode(responseBody)['error']);
} else {
customerProperty = CustomerProperty.fromJson(jsonDecode(responseBody));
}
} on FormatException {
throw new Exception(responseBody);
} on Exception catch (e) {
throw new Exception(e);
}
return customerProperty;
}
}
+17
View File
@@ -0,0 +1,17 @@
import 'package:workouttest_util/model/cache.dart';
import 'dart:convert';
import 'package:workouttest_util/model/exercise_device.dart';
import 'api.dart';
class ExerciseDeviceApi {
final APIClient _client = APIClient();
Future<List<ExerciseDevice>> getDevices() async {
final body = await _client.get("exercise_device/", "");
final Iterable json = jsonDecode(body);
final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
Cache().setDevices(devices);
return devices;
}
}
+44
View File
@@ -0,0 +1,44 @@
import 'dart:convert';
import 'package:workouttest_util/model/exercise.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/util/logging.dart';
class ExerciseApi with Logging {
final APIClient _client = APIClient();
Future<void> saveExercise(Exercise exercise) async {
String body = JsonEncoder().convert(exercise.toJson());
log(" ===== saving exercise id: " + exercise.exerciseId.toString() + ":" + body);
await _client.post("exercises/" + exercise.exerciseId.toString(), body);
}
Future<List<Exercise>> getExercisesByCustomer(int customerId) async {
final body = await _client.get("exercises/customer/", customerId.toString());
final Iterable json = jsonDecode(body);
final List<Exercise> exercises = json.map((exercise) {
Exercise item = Exercise.fromJson(exercise);
return item;
}).toList();
//exercises.sort( (a, b) => b.dateAdd.compareTo(a.dateAdd) );
return exercises;
}
Future<Exercise> addExercise(Exercise exercise) async {
String body = JsonEncoder().convert(exercise.toJson());
log(" ===== add new exercise: " + body);
final String response = await _client.post("exercises", body);
final Exercise savedExercise = Exercise.fromJson(jsonDecode(response));
return savedExercise;
}
Future<void> deleteExercise(Exercise exercise) async {
if (exercise.exerciseId == null) {
return;
}
int exerciseId = exercise.exerciseId!;
log(" ===== delete exercise: " + exerciseId.toString());
await _client.post("exercises/" + exerciseId.toString(), "");
return;
}
}
+82
View File
@@ -0,0 +1,82 @@
import 'dart:convert';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/exercise_tree.dart';
import 'package:workouttest_util/model/exercise_tree_parents.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:flutter/services.dart';
import 'api.dart';
class ExerciseTreeApi with Logging {
final APIClient _client = APIClient();
Future<List<ExerciseTree>> getExerciseTree() async {
final String body = await _client.get("exercise_tree", "");
Iterable json = jsonDecode(body);
List<ExerciseTree>? exerciseTrees = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
exerciseTrees = await getExerciseTreeParents(exerciseTrees);
await Future.forEach(exerciseTrees, (element) async {
ExerciseTree exerciseTree = element as ExerciseTree;
exerciseTree.imageUrl = await buildImage(exerciseTree.imageUrl, exerciseTree.treeId);
});
exerciseTrees = await getExerciseTreeParents(exerciseTrees);
log("ExerciseTree downloaded $exerciseTrees");
Cache().setExerciseTree(exerciseTrees);
return exerciseTrees;
}
Future<String> buildImage(String imageUrl, int treeId) async {
String assetImage = 'asset/menu/' + imageUrl.substring(7);
print("asset image $assetImage");
return await rootBundle.load(assetImage).then((value) {
return assetImage;
}).catchError((_) {
String imagePath = assetImage.substring(10);
String url = Cache.mediaUrl + 'images' + imagePath;
return url;
});
}
Future<List<ExerciseTree>> getExerciseTreeParents(List<ExerciseTree> exerciseTree) async {
List<ExerciseTree> copyList = this.copyList(exerciseTree);
final String body = await _client.get("exercise_tree_parents", "");
Iterable json = jsonDecode(body);
final List<ExerciseTreeParents> exerciseTreeParents =
json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
int treeIndex = 0;
copyList.forEach((element) async {
int index = 0;
exerciseTreeParents.forEach((parent) {
if (parent.exerciseTreeChildId == element.treeId) {
if (index > 0) {
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
newElement.sort = parent.sort;
exerciseTree.add(newElement);
} else {
element.parentId = parent.exerciseTreeParentId;
element.sort = parent.sort;
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
}
index++;
}
});
treeIndex++;
});
return exerciseTree;
}
List<ExerciseTree> copyList(List<ExerciseTree> tree) {
final List<ExerciseTree> copyList = [];
tree.forEach((element) {
final ExerciseTree copy = element.copy(-1);
copyList.add(copy);
});
return copyList;
}
}
+40
View File
@@ -0,0 +1,40 @@
import 'dart:convert';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/exercise_type.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:flutter/services.dart';
class ExerciseTypeApi with Logging {
final APIClient _client = APIClient();
Future<List<ExerciseType>> getExerciseTypes() async {
final body = await _client.get("exercise_type", "");
final Iterable json = jsonDecode(body);
final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
await Future.forEach(exerciseTypes, (element) async {
ExerciseType exerciseType = element as ExerciseType;
exerciseType.imageUrl = await buildImage(exerciseType.imageUrl, exerciseType.exerciseTypeId);
});
log("ExerciseTypes downloaded");
Cache().setExerciseTypes(exerciseTypes);
return exerciseTypes;
}
Future<String> buildImage(String imageUrl, int exerciseTypeId) async {
if (imageUrl.length > 8) {
String assetImage = 'asset/menu/' + imageUrl.substring(7);
return rootBundle.load(assetImage).then((value) {
return assetImage;
}).catchError((_) {
String imagePath = assetImage.substring(10);
String url = Cache.mediaUrl + 'images' + imagePath;
return url;
});
} else {
return imageUrl;
}
}
}
+403
View File
@@ -0,0 +1,403 @@
import 'dart:math' as math;
import 'dart:convert';
// ignore: depend_on_referenced_packages
import 'package:crypto/crypto.dart';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/util/logging.dart' as logger;
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'package:firebase_auth/firebase_auth.dart';
// ignore: depend_on_referenced_packages
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:firebase_remote_config/firebase_remote_config.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
class FirebaseApi with logger.Logging {
bool appleSignInAvailable = false;
static final FirebaseAuth auth = FirebaseAuth.instance;
static const String SIGN_IN_OK = "OK";
static const String SIGN_IN_NOT_FOUND = "user-not-found";
static const String SIGN_IN_WRONG_PWD = "wrong-password";
static const String REGISTER_WEAK_PWD = "weak-password";
static const String REGISTER_EMAIL_IN_USE = "email-already-in-use";
late UserCredential userCredential;
String? firebaseRegToken;
factory FirebaseApi() => FirebaseApi._internal();
FirebaseApi._internal();
// Define an async function to initialize FlutterFire
Future<void> initializeFlutterFire() async {
try {
// Wait for Firebase to initialize and set `_initialized` state to true
await Firebase.initializeApp();
this.appleSignInAvailable = await SignInWithApple.isAvailable();
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
this.firebaseRegToken = await FirebaseMessaging.instance.getToken();
Cache().firebaseMessageToken = firebaseRegToken;
log("FirebaseMessaging token $firebaseRegToken");
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
} catch (e) {
// Set `_error` state to true if Firebase initialization fails
Sentry.captureException(e);
log("Error initializing Firebase");
}
}
Future<String> signInEmail(String? email, String? password) async {
if (email == null) {
throw Exception("Please type an email address");
}
if (password == null) {
throw Exception("Password too short");
}
String rc = SIGN_IN_OK;
try {
userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
Cache().firebaseUid = userCredential.user!.uid;
} on FirebaseAuthException catch (e) {
Sentry.captureException(e);
if (e.code == 'user-not-found') {
log('No user found for that email.');
rc = SIGN_IN_NOT_FOUND;
} else if (e.code == 'wrong-password') {
log('Wrong password provided for that user.');
rc = SIGN_IN_WRONG_PWD;
throw Exception("Customer does not exist or the password is wrong");
}
return e.code;
}
return rc;
}
Future<String> registerEmail(String email, String password) async {
String rc = SIGN_IN_OK;
try {
userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password);
Cache().firebaseUid = userCredential.user!.uid;
} on FirebaseAuthException catch (e) {
Sentry.captureException(e);
if (e.code == 'weak-password') {
log('The password provided is too weak.');
rc = REGISTER_WEAK_PWD;
throw Exception("Password too short");
} else if (e.code == 'email-already-in-use') {
log('The account already exists for that email.');
rc = REGISTER_EMAIL_IN_USE;
throw Exception("The email address has been registered already");
}
} catch (e) {
log(e.toString());
Sentry.captureException(e);
throw Exception(e.toString());
}
return rc;
}
String generateNonce([int length = 32]) {
final charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
final random = math.Random.secure();
return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join();
}
/// Returns the sha256 hash of [input] in hex notation.
String sha256ofString(String input) {
final bytes = utf8.encode(input);
final digest = sha256.convert(bytes);
return digest.toString();
}
Future<Map<String, dynamic>> signInWithApple() async {
Map<String, dynamic> userData = Map();
// To prevent replay attacks with the credential returned from Apple, we
// include a nonce in the credential request. When signing in with
// Firebase, the nonce in the id token returned by Apple, is expected to
// match the sha256 hash of `rawNonce`.
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
);
// Create an `OAuthCredential` from the credential returned by Apple.
final oauthCredential = OAuthProvider("apple.com").credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
UserCredential? userCredential;
try {
// Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
} on FirebaseAuthException catch(e) {
Sentry.captureException(e);
throw Exception(e);
}
Cache().firebaseUid = userCredential.user!.uid;
log("userCredential: " + userCredential.toString());
log("Apple Credentials: ${appleCredential.userIdentifier} state ${appleCredential.state} email ${userCredential.user!.email!}");
userData['email'] = userCredential.user!.email;
return userData;
}
Future<Map<String, dynamic>> registerWithApple() async {
Map<String, dynamic> userData = Map();
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
// Request credential for the currently signed in Apple account.
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
);
final oauthCredential = OAuthProvider("apple.com").credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
UserCredential? userCredential;
try {
// Sign in the user with Firebase. If the nonce we generated earlier does
// not match the nonce in `appleCredential.identityToken`, sign in will fail.
userCredential = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
} on FirebaseAuthException catch(e) {
Sentry.captureException(e);
throw Exception(e);
}
Cache().firebaseUid = userCredential.user!.uid;
userData['email'] = userCredential.user!.email;
return userData;
}
Future<Map<String, dynamic>> signInWithGoogle() async {
Map<String, dynamic> userData = Map();
// Trigger the authentication flow
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
if (googleUser == null) {
Sentry.captureException(new Exception("Google Sign In failed"));
throw Exception("Google Sign In failed");
}
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
// Create a new credential
final OAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
Cache().firebaseUid = userCredential.user!.uid;
log("GoogleUser: " + googleUser.toString());
userData['email'] = googleUser.email;
userData['id'] = googleUser.id;
userData['name'] = googleUser.displayName;
return userData;
}
Future<Map<String, dynamic>> registerWithGoogle() async {
Map<String, dynamic> userData = Map();
// Trigger the authentication flow
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: [
'email',
'https://www.googleapis.com/auth/contacts.readonly',
],
);
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
if (googleUser == null) {
Sentry.captureException(new Exception("Google Sign In failed"));
throw Exception("Google Sign In failed");
}
// Obtain the auth details from the request
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
// Create a new credential
final OAuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
final userCredential = await FirebaseAuth.instance.signInWithCredential(credential);
log("Google credentials: " + credential.toString() + " GoogleUser: " + googleUser.toString());
Cache().firebaseUid = userCredential.user!.uid;
userData['email'] = googleUser.email;
return userData;
}
Future<Map<String, dynamic>> signInWithFacebook() async {
Map<String, dynamic> userData;
// by default the login method has the next permissions ['email','public_profile']
final LoginResult result = await FacebookAuth.instance.login();
if (result.status == LoginStatus.success) {
final AccessToken accessToken = result.accessToken!;
log(accessToken.toJson().toString());
Cache().accessTokenFacebook = accessToken;
// get the user data
userData = await FacebookAuth.instance.getUserData();
Cache().firebaseUid = userData['id'];
log(userData.toString());
} else {
Sentry.captureException(new Exception(result.message));
throw Exception("Facebook login was not successful");
}
return userData;
}
Future<Map<String, dynamic>> registerWithFacebook() async {
Map<String, dynamic> userData;
// by default the login method has the next permissions ['email','public_profile']
final LoginResult result = await FacebookAuth.instance.login();
if (result.status == LoginStatus.success) {
final AccessToken accessToken = result.accessToken!;
Cache().accessTokenFacebook = accessToken;
// get the user data
userData = await FacebookAuth.instance.getUserData();
log("FB user data: " + userData.toString());
// Create a credential from the access token
final OAuthCredential facebookAuthCredential = FacebookAuthProvider.credential(accessToken.token);
// Once signed in, return the UserCredential
final userCredential = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
log("Email by FB: " + userData['email'] + " FB credential: " + userCredential.toString());
Cache().firebaseUid = userCredential.user!.uid;
} else {
Sentry.captureException(new Exception(result.message));
throw Exception("Facebook login was not successful");
}
return userData;
}
Future<void> logOutFacebook() async {
await FacebookAuth.instance.logOut();
Cache().accessTokenFacebook = null;
}
Future<void> signOut() async {
await FirebaseAuth.instance.signOut();
}
Future<void> resetPassword(String email) async {
await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
}
Future<void> setupRemoteConfig() async {
//initializeFlutterFire();
FirebaseRemoteConfig? remoteConfig;
try {
remoteConfig = FirebaseRemoteConfig.instance;
await remoteConfig.setConfigSettings(RemoteConfigSettings(
fetchTimeout: const Duration(seconds: 10),
minimumFetchInterval: const Duration(seconds: 1),
));
//RemoteConfigValue(null, ValueSource.valueStatic);
//Cache().setRemoteConfig(remoteConfig);
} on Exception catch (e) {
print('Unable to fetch remote config. Cached or default values will be used: $e');
if (remoteConfig != null) {
await remoteConfig.setDefaults(<String, dynamic>{
'sales_page_text_a': '',
'product_set_2': '',
'registration_skip_color': '',
'email_checkbox': '',
});
Cache().setRemoteConfig(remoteConfig);
}
}
}
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
print('Handling a background message ${message.messageId}');
}
/* Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print('Handling a background message: ${message.messageId}');
if (!StringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
!StringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)) {
print('message also contained a notification: ${message.notification}');
String? imageUrl;
imageUrl ??= message.notification!.android?.imageUrl;
imageUrl ??= message.notification!.apple?.imageUrl;
Map<String, dynamic> notificationAdapter = {
NOTIFICATION_CHANNEL_KEY: 'basic_channel',
NOTIFICATION_ID: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_ID] ?? message.messageId ?? math.Random().nextInt(2147483647),
NOTIFICATION_TITLE: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_TITLE] ?? message.notification?.title,
NOTIFICATION_BODY: message.data[NOTIFICATION_CONTENT]?[NOTIFICATION_BODY] ?? message.notification?.body,
NOTIFICATION_LAYOUT: StringUtils.isNullOrEmpty(imageUrl) ? 'Default' : 'BigPicture',
NOTIFICATION_BIG_PICTURE: imageUrl
};
AwesomeNotifications().createNotificationFromJsonData(notificationAdapter);
} else {
AwesomeNotifications().createNotificationFromJsonData(message.data);
}
} */
+29
View File
@@ -0,0 +1,29 @@
import 'dart:io';
import 'package:workouttest_util/model/mautic.dart';
import 'package:workouttest_util/util/logging.dart';
class MauticApi with Logging {
final String mauticUrl = "https://mautic.workouttest.org/form/submit?formId=";
Future<void> sendMauticForm(Mautic model) async {
final String body = model.toForm();
log(" ===== mautic subscription: $body");
HttpClient client = HttpClient();
String url = mauticUrl + model.formId.toString();
var uri = Uri.parse(url);
final HttpClientRequest request = await client.postUrl(uri);
request.headers.set('Content-Type', 'application/x-www-form-urlencoded');
request.headers.set('cache-control', 'no-cache');
request.write(body);
HttpClientResponse result = await request.close();
client.close();
if (!(result.statusCode == 200 || result.statusCode == 302)) {
trace("mautic response: ${result.statusCode}");
//throw Exception("Network error, try again later!");
}
}
}
+210
View File
@@ -0,0 +1,210 @@
import 'dart:convert';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/customer.dart';
import 'package:workouttest_util/model/customer_activity.dart';
import 'package:workouttest_util/model/customer_exercise_device.dart';
import 'package:workouttest_util/model/customer_property.dart';
import 'package:workouttest_util/model/description.dart';
import 'package:workouttest_util/model/evaluation.dart';
import 'package:workouttest_util/model/exercise.dart';
import 'package:workouttest_util/model/exercise_device.dart';
import 'package:workouttest_util/model/exercise_plan_template.dart';
import 'package:workouttest_util/model/exercise_tree.dart';
import 'package:workouttest_util/model/exercise_tree_parents.dart';
import 'package:workouttest_util/model/exercise_type.dart';
import 'package:workouttest_util/model/faq.dart';
import 'package:workouttest_util/model/product.dart';
import 'package:workouttest_util/model/property.dart';
import 'package:workouttest_util/model/purchase.dart';
import 'package:workouttest_util/model/split_test.dart';
import 'package:workouttest_util/model/training_plan.dart';
import 'package:workouttest_util/model/training_plan_day.dart';
import 'package:workouttest_util/model/tutorial.dart';
import 'package:workouttest_util/repository/training_plan_day_repository.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/service/exercise_type_service.dart';
import 'package:workouttest_util/util/not_found_exception.dart';
import '../model/sport.dart';
import 'customer_service.dart';
import 'exercise_tree_service.dart';
class PackageApi {
final APIClient _client = APIClient();
Future<void> getPackage() async {
late List<ExerciseTree> exerciseTree;
late List<ExerciseTreeParents> exerciseTreeParents;
final body = await _client.get("app_package/", "");
final List<String> models = body.split("|||");
await Future.forEach(models, (elem) async {
final String element = elem as String;
final List<String> headRecord = element.split("***");
final Iterable json = jsonDecode(headRecord[1]);
if (headRecord[0] == "ExerciseDevice") {
final List<ExerciseDevice> devices = json.map((device) => ExerciseDevice.fromJson(device)).toList();
Cache().setDevices(devices);
} else if (headRecord[0] == "Product") {
final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
Cache().setProducts(products);
} else if (headRecord[0] == "Property") {
final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
Cache().setProperties(properties);
} else if (headRecord[0] == "ExerciseTree") {
exerciseTree = json.map((exerciseTree) => ExerciseTree.fromJson(exerciseTree)).toList();
} else if (headRecord[0] == "ExerciseType") {
final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
await Future.forEach(exerciseTypes, (elem) async {
final ExerciseType exerciseType = elem as ExerciseType;
exerciseType.imageUrl = await ExerciseTypeApi().buildImage(exerciseType.imageUrl, exerciseType.exerciseTypeId);
});
Cache().setExerciseTypes(exerciseTypes);
} else if (headRecord[0] == "ExerciseAbility") {
} else if (headRecord[0] == "ExercisePlanTemplate") {
final List<ExercisePlanTemplate> exercisePlanTemplates =
json.map((exercisePlanTemplate) => ExercisePlanTemplate.fromJson(exercisePlanTemplate)).toList();
Cache().setExercisePlanTemplates(exercisePlanTemplates);
} else if (headRecord[0] == "ExerciseTreeParents") {
exerciseTreeParents = json.map((exerciseTreeParent) => ExerciseTreeParents.fromJson(exerciseTreeParent)).toList();
} else if (headRecord[0] == "Evaluation") {
final List<Evaluation> evaluations = json.map((evaluation) => Evaluation.fromJson(evaluation)).toList();
Cache().evaluations = evaluations;
} else if (headRecord[0] == "Sport") {
final List<Sport> sports = json.map((sport) => Sport.fromJson(sport)).toList();
Cache().setSports(sports);
} else if (headRecord[0] == "Tutorial") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Tutorial> tutorials = json.map((tutorial) => Tutorial.fromJson(tutorial)).toList();
Cache().setTutorials(tutorials);
} else if (headRecord[0] == "Description") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Description>? descriptions = json.map((description) => Description.fromJson(description)).toList();
//print("Description: $descriptions");
Cache().setDescriptions(descriptions);
} else if (headRecord[0] == "Faq") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Faq>? faqs = json.map((faq) => Faq.fromJson(faq)).toList();
//print("Faq: $faqs");
Cache().setFaqs(faqs);
} else if (headRecord[0] == "TrainingPlan") {
final Iterable json = jsonDecode(headRecord[1]);
final List<TrainingPlan>? plans = json.map((plan) => TrainingPlan.fromJson(plan)).toList();
List<TrainingPlan> activePlans = [];
if (plans != null) {
plans.forEach((element) {
if (element.active) {
activePlans.add(element);
}
});
}
Cache().setTrainingPlans(activePlans);
} else if (headRecord[0] == "SplitTests") {
final Iterable json = jsonDecode(headRecord[1]);
final List<SplitTest>? tests = json.map((test) => SplitTest.fromJson(test)).toList();
//print("A/B tests: $tests");
Cache().setSplitTests(tests);
} else if (headRecord[0] == "TrainingPlanDay") {
final Iterable json = jsonDecode(headRecord[1]);
final List<TrainingPlanDay>? days = json.map((day) => TrainingPlanDay.fromJson(day)).toList();
Cache().setTrainingPlanDays(days);
}
});
exerciseTree = this.getExerciseTreeParents(exerciseTree, exerciseTreeParents);
await Future.forEach(exerciseTree, (element) async {
ExerciseTree tree = element as ExerciseTree;
tree.imageUrl = await ExerciseTreeApi().buildImage(tree.imageUrl, tree.treeId);
});
Cache().setExerciseTree(exerciseTree);
TrainingPlanDayRepository trainingPlanDayRepository = TrainingPlanDayRepository();
trainingPlanDayRepository.assignTrainingPlanDays();
return;
}
List<ExerciseTree> getExerciseTreeParents(final List<ExerciseTree> exerciseTree, final List<ExerciseTreeParents> exerciseTreeParents) {
List<ExerciseTree> copyList = ExerciseTreeApi().copyList(exerciseTree);
int treeIndex = 0;
copyList.forEach((element) async {
int index = 0;
exerciseTreeParents.forEach((parent) {
if (parent.exerciseTreeChildId == element.treeId) {
if (index > 0) {
ExerciseTree newElement = element.copy(parent.exerciseTreeParentId);
newElement.sort = parent.sort;
exerciseTree.add(newElement);
} else {
element.parentId = parent.exerciseTreeParentId;
element.sort = parent.sort;
exerciseTree[treeIndex].parentId = parent.exerciseTreeParentId;
exerciseTree[treeIndex].sort = parent.sort;
}
index++;
}
});
treeIndex++;
});
return exerciseTree;
}
Future<void> getCustomerPackage(int customerId) async {
try {
final body = await _client.get("app_customer_package/" + customerId.toString(), "");
final List<String> models = body.split("|||");
await Future.forEach(models, (elem) async {
final String element = elem as String;
final List<String> headRecord = element.split("***");
//print("Class " + headRecord[0]);
if (headRecord[0] == "Customer") {
Customer customer = Customer.fromJson(jsonDecode(headRecord[1]));
Cache().userLoggedIn = customer;
} else if (headRecord[0] == "CustomerExerciseDevice") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerExerciseDevice> devices = json.map((device) => CustomerExerciseDevice.fromJson(device)).toList();
Cache().setCustomerDevices(devices);
// ToDo
} else if (headRecord[0] == "Exercises") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Exercise> exercises = json.map((exerciseType) => Exercise.fromJson(exerciseType)).toList();
Cache().setExercises(exercises);
} else if (headRecord[0] == "Purchase") {
final Iterable json = jsonDecode(headRecord[1]);
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
Cache().setPurchases(purchases);
} else if (headRecord[0] == "CustomerProperty") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerProperty> customerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList();
CustomerApi().initProperties(customerProperties);
} else if (headRecord[0] == "CustomerPropertyAll") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerProperty> allCustomerProperties = json.map((property) => CustomerProperty.fromJson(property)).toList();
print(" All Properties ---- $allCustomerProperties");
Cache().setCustomerPropertyAll(allCustomerProperties);
} else if (headRecord[0] == "ExerciseResult") {
/*final Iterable json = jsonDecode(headRecord[1]);
final List<ExerciseResult> exerciseResults = json.map((exerciseResult) {
ExerciseResult item = ExerciseResult.fromJson(exerciseResult);
return item;
}).toList();
// ToDo */
} else if (headRecord[0] == "CustomerActivity") {
final Iterable json = jsonDecode(headRecord[1]);
final List<CustomerActivity> customerActivities = json.map((activity) => CustomerActivity.fromJson(activity)).toList();
Cache().setCustomerActivities(customerActivities);
}
});
} on NotFoundException catch (e) {
throw Exception("Please log in $e");
}
}
}
+17
View File
@@ -0,0 +1,17 @@
import 'dart:convert';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/product.dart';
import 'package:workouttest_util/service/api.dart';
class ProductApi {
final APIClient _client = APIClient();
Future<List<Product>> getProducts() async {
final body = await _client.get("product/", "");
final Iterable json = jsonDecode(body);
final List<Product> products = json.map((product) => Product.fromJson(product)).toList();
Cache().setProducts(products);
return products;
}
}
+18
View File
@@ -0,0 +1,18 @@
import 'dart:convert';
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/model/property.dart';
class PropertyApi {
final APIClient _client = APIClient();
Future<List<Property>> getProperties() async {
final body = await _client.get("property/", "");
final Iterable json = jsonDecode(body);
final List<Property> properties = json.map((property) => Property.fromJson(property)).toList();
Cache().setProperties(properties);
return properties;
}
}
+29
View File
@@ -0,0 +1,29 @@
import 'package:workouttest_util/model/cache.dart';
import 'package:workouttest_util/model/purchase.dart';
import 'package:workouttest_util/util/logging.dart';
import 'package:workouttest_util/util/not_found_exception.dart';
import 'dart:convert';
import 'api.dart';
class PurchaseApi with Logging {
final APIClient _client = APIClient();
Future<List<Purchase>> getPurchasesByCustomer(int customerId) async {
List<Purchase> purchases = [];
try {
final body = await _client.get("purchase/customer/" + customerId.toString(), "");
final Iterable json = jsonDecode(body);
final List<Purchase> purchases = json.map((purchase) => Purchase.fromJson(purchase)).toList();
Cache().setPurchases(purchases);
} on NotFoundException catch (_) {
log("No purchases found");
}
return purchases;
}
Future<void> savePurchase(Purchase purchase) async {
String body = JsonEncoder().convert(purchase.toJson());
log(" ===== saving purchase:" + body);
await _client.post("purchase/", body);
}
}
+18
View File
@@ -0,0 +1,18 @@
import 'package:workouttest_util/model/tracking.dart';
import 'package:workouttest_util/util/logging.dart';
import 'dart:convert';
import 'api.dart';
class TrackingApi with Logging {
final APIClient _client = APIClient();
Future<void> saveTracking(Tracking tracking) async {
try {
String body = const JsonEncoder().convert(tracking.toJson());
log(" ===== saving tracking: $body");
await _client.post("tracking/", body);
} catch (exception) {
log("exception in tracking: ${exception.toString()}");
}
}
}
+34
View File
@@ -0,0 +1,34 @@
import 'dart:convert';
import 'package:workouttest_util/model/customer_training_plan.dart';
import 'package:workouttest_util/model/customer_training_plan_exercise.dart';
import 'package:workouttest_util/service/api.dart';
import 'package:workouttest_util/util/logging.dart';
class TrainingPlanApi with Logging {
final APIClient _client = APIClient();
Future<CustomerTrainingPlan> saveCustomerTrainingPlan(CustomerTrainingPlan plan) async {
String body = JsonEncoder().convert(plan.toJson());
log(" ===== saving customer training plan:" + body);
final String response = await _client.post("customer_training_plan/", body);
final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response));
return saved;
}
Future<CustomerTrainingPlanExercise> saveCustomerTrainingPlanExercise(CustomerTrainingPlanExercise planExercise) async {
String body = JsonEncoder().convert(planExercise.toJson());
log(" ===== saving customer training plan exercise:" + body);
final String response = await _client.post("customer_training_plan_exercise/", body);
final CustomerTrainingPlanExercise saved = CustomerTrainingPlanExercise.fromJson(jsonDecode(response));
return saved;
}
Future<CustomerTrainingPlan> updateCustomerTrainingPlan(CustomerTrainingPlan plan, int customerTrainingPlanId) async {
String body = JsonEncoder().convert(plan.toJson());
log(" ===== update customer training plan:" + body);
final String response = await _client.post("customer_training_plan/update/$customerTrainingPlanId", body);
final CustomerTrainingPlan saved = CustomerTrainingPlan.fromJson(jsonDecode(response));
return saved;
}
}