import 'package:comunic/helpers/api_helper.dart'; import 'package:comunic/helpers/preferences_helper.dart'; import 'package:comunic/helpers/websocket_helper.dart'; import 'package:comunic/models/api_request.dart'; import 'package:comunic/models/authentication_details.dart'; import 'package:comunic/models/login_tokens.dart'; import 'package:comunic/models/new_account.dart'; import 'package:shared_preferences/shared_preferences.dart'; /// Account helper /// /// @author Pierre HUBERT enum AuthResult { SUCCESS, TOO_MANY_ATTEMPTS, NETWORK_ERROR, INVALID_CREDENTIALS } enum CreateAccountResult { SUCCESS, ERROR_TOO_MANY_REQUESTS, ERROR_EXISTING_EMAIL, ERROR } class AccountHelper { static const _USER_ID_PREFERENCE_NAME = "user_id"; // Current user ID static int _currentUserID = -1; /// Checkout whether current user is signed in or not /// /// Warning : This method MUST BE CALLED AT LEAST ONCE AFTER APP START !!! Future signedIn() async { bool signedIn = (await PreferencesHelper.getInstance()).getLoginTokens() != null; // Load current user ID for later use if (signedIn && _currentUserID == -1) await _loadCurrentUserID(); return signedIn; } /// Sign in user Future signIn(AuthenticationDetails auth) async { final request = APIRequest(uri: "account/login"); request.addString("userMail", auth.email); request.addString("userPassword", auth.password); final response = await APIHelper().exec(request); // Handle errors if (response.code == 401) return AuthResult.INVALID_CREDENTIALS; else if (response.code == 429) return AuthResult.TOO_MANY_ATTEMPTS; else if (response.code != 200) return AuthResult.NETWORK_ERROR; // Save login tokens final tokensObj = response.getObject()["tokens"]; await (await PreferencesHelper.getInstance()) .setLoginTokens(LoginTokens(tokensObj["token1"], tokensObj["token2"])); // Get current user ID final userID = await _downloadCurrentUserID(); if (userID == null) { await signOut(); // We can not stay signed in without current user ID return AuthResult.NETWORK_ERROR; } // Save current user ID final preferences = await SharedPreferences.getInstance(); await preferences.setInt(_USER_ID_PREFERENCE_NAME, userID); _currentUserID = userID; return AuthResult.SUCCESS; } /// Sign out user Future signOut() async { await (await PreferencesHelper.getInstance()).setLoginTokens(null); _currentUserID = 0; // Close current web socket WebSocketHelper.close(); } /// Create a new user account Future createAccount(NewAccount info) async { final response = await APIRequest( uri: "account/create", needLogin: false, args: { "firstName": info.firstName, "lastName": info.lastName, "emailAddress": info.email, "password": info.password, }, ).exec(); switch (response.code) { case 200: return CreateAccountResult.SUCCESS; case 409: return CreateAccountResult.ERROR_EXISTING_EMAIL; case 429: return CreateAccountResult.ERROR_TOO_MANY_REQUESTS; default: return CreateAccountResult.ERROR; } } /// Check out whether a given email address exists or not /// /// Throws in case of failure static Future existsMailAccount(String email) async => (await APIRequest.withoutLogin("account/exists_email") .addString("email", email) .execWithThrow()) .getObject()["exists"]; /// Check out whether security questions have been set for an account or not /// /// Throws in case of failure static Future hasSecurityQuestions(String email) async => (await APIRequest.withoutLogin("account/has_security_questions") .addString("email", email) .execWithThrow()) .getObject()["defined"]; /// Get current user ID from the server Future _downloadCurrentUserID() async { final response = await APIRequest( uri: "user/getCurrentUserID", needLogin: true, ).exec(); if (response.code != 200) return null; return response.getObject()["userID"]; } /// Get the ID of the currently signed in user Future _loadCurrentUserID() async { final preferences = await SharedPreferences.getInstance(); _currentUserID = preferences.getInt(_USER_ID_PREFERENCE_NAME); } /// Get the ID of the currently signed in user static int getCurrentUserID() { if (_currentUserID == -1) throw "Current user ID has not been loaded yet!"; return _currentUserID; } /// Disconnect all the devices of the current user /// /// Throws in case of failure static Future disconnectAllDevices() async { await APIRequest(uri: "account/disconnect_all_devices", needLogin: true) .execWithThrow(); } /// Remove permanently a user account /// /// Throws in case of failure static Future deleteAccount(String password) async { await APIRequest(uri: "account/delete", needLogin: true) .addString("password", password) .execWithThrow(); } }