/// <summary> /// When a user wants to subscribe to a quiz /// </summary> /// <param name="sender"></param> /// <param name="e"></param> async private void ImageButtonSubscribe_Clicked(object sender, EventArgs e) { if (CredentialManager.IsLoggedIn) { ImageButton button = (sender as ImageButton); string dbId = button.StyleId; ActivityIndicator indicatorSyncing = (button.Parent as StackLayout).Children[(int)SubscribeUtils.SubscribeType.Syncing] as ActivityIndicator; button.IsVisible = false; indicatorSyncing.IsVisible = true; indicatorSyncing.IsRunning = true; OperationReturnMessage returnMessage = await SubscribeUtils.SubscribeToQuizAsync(dbId, this.quizzesFeatured); if (returnMessage == OperationReturnMessage.True) { (button.Parent as StackLayout).Children[2].IsVisible = true; // add in unsubscribe button } else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials) { button.IsVisible = true; await this.DisplayAlert("Invalid Credentials", "Your current login credentials are invalid. Please try logging in again.", "OK"); } else { button.IsVisible = true; await this.DisplayAlert("Subscribe Failed", "The subscription request could not be completed. Please try again.", "OK"); } indicatorSyncing.IsVisible = false; // remove activity indicator indicatorSyncing.IsRunning = false; } else { await this.DisplayAlert("Hold on!", "Before you can subscribe to any quizzes, you have to login.", "Ok"); } }
/// <summary> /// Triggered when continue is clicked; checks if the user has an account to recover password for /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonContinue_Clicked(object sender, EventArgs e) { this.ActivityIndicator.IsVisible = true; this.ActivityIndicator.IsRunning = true; this.LabelMessage.Text = ""; if (this.EntryUsername.Text != null) { this.username = this.EntryUsername.Text.Trim(); OperationReturnMessage message = await Task.Run(() => ServerOperations.ForgotPassword(this.username)); if (message == OperationReturnMessage.True) { this.StackLayoutResetPassword.IsVisible = true; } else if (message == OperationReturnMessage.FalseInvalidCredentials) { this.LabelMessage.Text = "Username was not found."; } else { this.LabelMessage.Text = "Could not connect to server. Please try again."; } } else { await this.DisplayAlert("Empty Field", "Username cannot be empty.", "Ok"); } this.ActivityIndicator.IsVisible = false; this.ActivityIndicator.IsRunning = false; }
/// <summary> /// Confirm the email associated with the account. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonConfirmEmail_Clicked(object sender, EventArgs e) { if (this.SetupFrameBegin(this.FrameConfirmEmail, this.StackLayoutConfirmEmailContent)) { string token = this.EntryEnterConfirmationCodeConfirmEmail.Text.Trim(); OperationReturnMessage message = await Task.Run(() => this.ConfirmEmail(token)); if (message == OperationReturnMessage.True) { this.LabelConfirmEmailMessage.Text = "Email was confirmed."; CredentialManager.EmailConfirmed = true; this.FrameConfirmEmail.IsVisible = false; await this.DisplayAlert("Email Confirmation", "Email was confirmed", "OK"); } else if (message == OperationReturnMessage.FalseNoConnection) { this.LabelDeleteAccountMessage.Text = "Failed to connect to server. Please try again."; } else { this.LabelConfirmEmailMessage.Text = "Email confirmation code was incorrect."; } } this.SetupFrameEnd(this.StackLayoutConfirmEmailContent); }
/// <summary> /// Triggered when change password is clicked; asks the server to change the password /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonChangePassword_Clicked(object sender, EventArgs e) { this.ActivityIndicator.IsVisible = true; this.ActivityIndicator.IsRunning = true; if (this.EntryPassword.Text == this.EntryReenterPassword.Text && this.EntryPassword.Text.Length > minLength) { OperationReturnMessage message = ServerOperations.ForgotPasswordChangePassword(this.username, this.EntryCode.Text.Trim(), this.EntryPassword.Text.Trim()); if (message == OperationReturnMessage.True) { await this.DisplayAlert("Password Changed", "Your password was sucessfully changed.", "Ok"); await this.Navigation.PopModalAsync(); } else if (message == OperationReturnMessage.FalseInvalidCredentials) { await this.DisplayAlert("Incorrect Code", "Your code was incorrect. Please try again.", "Ok"); } else { await this.DisplayAlert("Failed", "Your password change was failed. Please try again.", "Ok"); } } else { await this.DisplayAlert("Invalid fields", "Passwords do not match or are not greater than five characters or less than 32 characters", "Ok"); } this.ActivityIndicator.IsVisible = false; this.ActivityIndicator.IsRunning = false; }
/// <summary> /// Delete the user's acccount. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonDeleteAccount_Clicked(object sender, EventArgs e) { if (this.SetupFrameBegin(this.FrameDeleteAccount, this.StackLayoutDeleteAccountContent)) { bool confirmed = await this.DisplayAlert("Confirm Delete", "" + "Are you sure you want to delete your account? Your account cannot be recovered, and all created quizzes will be deleted.", "Yes", "No"); if (confirmed) { string password = this.EntryEnterPasswordDeleteAccount.Text.Trim(); OperationReturnMessage message = await Task.Run(() => this.DeleteAccount(password)); if (message == OperationReturnMessage.True) { CredentialManager.Logout(true); await this.DisplayAlert("Account Deletion", "Account successfully deleted", "OK"); this.OnSignedOut(); await this.Navigation.PopAsync(); } else if (message == OperationReturnMessage.FalseNoConnection) { this.LabelDeleteAccountMessage.Text = "Failed to connect to server. Please try again."; } else { this.LabelDeleteAccountMessage.Text = "Incorrect password. Please try again."; } } } this.SetupFrameEnd(this.StackLayoutDeleteAccountContent); }
/// <summary> /// Change the email of the account. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonChangeEmail_Clicked(object sender, EventArgs e) { if (this.SetupFrameBegin(this.FrameChangeEmail, this.StackLayoutChangeEmailContent)) { OperationReturnMessage message = await Task.Run(() => this.ChangeEmail( this.EntryEnterPasswordChangeEmail.Text, this.EntryEnterNewEmailChangeEmail.Text)); if (message == OperationReturnMessage.TrueConfirmEmail) { this.LabelChangeEmailMessage.Text = "Email Changed. Please Confirm Email."; EmailConfirmationPage emailConfirmationPage = new EmailConfirmationPage( CredentialManager.Username, this.EntryEnterPasswordChangeEmail.Text); emailConfirmationPage.EmailConfirmed += this.OnEmailConfirmed; emailConfirmationPage.ConfirmLaterSelected += this.OnConfirmLaterSelected; await this.Navigation.PushModalAsync(emailConfirmationPage, true); } else if (message == OperationReturnMessage.FalseInvalidCredentials) { this.LabelChangeEmailMessage.Text = "Incorrect password."; } else if (message == OperationReturnMessage.FalseInvalidEmail) { this.LabelChangeEmailMessage.Text = "Invalid email. Please check the email and try again."; } else if (message == OperationReturnMessage.FalseNoConnection) { this.LabelDeleteAccountMessage.Text = "Failed to connect to server. Please try again."; } } this.SetupFrameEnd(this.StackLayoutChangeEmailContent); }
/// <summary> /// Unsubscribe from a quiz /// </summary> /// <param name="dbId">ID to unsub from</param> /// <returns>If the unsub was successful</returns> public static async Task <OperationReturnMessage> UnsubscribeFromQuizAsync(string dbId) { QuizInfo info = QuizRosterDatabase.GetQuizInfo(dbId); if (info.SyncStatus != (int)SyncStatusEnum.NotDownloadedAndNeedDownload) { string location = App.UserPath + "/" + info.Category + "/" + info.QuizName + "`" + info.AuthorName; if (Directory.Exists(location)) { Directory.Delete(location, true); } } OperationReturnMessage returnMessage = await Task.Run(async() => await ServerOperations.UnsubscribeToQuizAsync(dbId)); if (returnMessage == OperationReturnMessage.True) { QuizRosterDatabase.DeleteQuizInfo(dbId); return(returnMessage); } else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials) { CredentialManager.IsLoggedIn = false; return(returnMessage); } else { return(returnMessage); } }
/// <summary> /// Send a quiz to the server with the current user credentials. /// </summary> /// <param name="relativeQuizPath">The path to the quiz on the current device.</param> /// <returns>A bool wrapped in a task representing whether the quiz successfully sent or not.</returns> public async static Task <bool> SendQuiz(string relativeQuizPath) { try { string realmFilePath = Directory.GetFiles(App.UserPath + relativeQuizPath, "*.realm").First(); Realm realm = Realm.GetInstance(App.realmConfiguration(realmFilePath)); QuizInfo info = realm.All <QuizInfo>().First(); if (await SendRealmFile(realmFilePath) != OperationReturnMessage.True) { throw new Exception(); } string[] imageFilePaths = Directory.GetFiles(App.UserPath + relativeQuizPath, "*.jpg"); for (int i = 0; i < imageFilePaths.Length; i++) { //[0] = path, [1] = fileName, [2] = dBId string fileName = imageFilePaths[i].Split('/').Last().Split('.').First(); string dbID = info.DBId; OperationReturnMessage message = await SendImageFile(imageFilePaths[i], fileName, dbID); if (message == OperationReturnMessage.False) { throw new Exception(); } } // When finished, confirm with server that quiz send has completed OperationReturnMessage finalizationMessage = (OperationReturnMessage)SendStringData( $"{info.DBId}`{info.LastModifiedDate}`{imageFilePaths.Length + 1}`" + $"{CredentialManager.Username}`{await SecureStorage.GetAsync("password")}`-", ServerRequestTypes.FinalizeQuizSend); if (finalizationMessage == OperationReturnMessage.True) { QuizInfo infoCopy = new QuizInfo(info) { SyncStatus = (int)SyncStatusEnum.Synced }; QuizRosterDatabase.EditQuizInfo(infoCopy); return(true); } else { throw new Exception(); } } catch (Exception ex) { string test = ex.ToString(); // Alert server that quiz send failed Delete records return(false); } }
/// <summary> /// Create a new account. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonCreateAccount_Clicked(object sender, EventArgs e) { this.ButtonCreateAccount.IsEnabled = false; this.EntryEmail.IsEnabled = false; this.EntryPassword.IsEnabled = false; this.EntryUsername.IsEnabled = false; this.ActivityIndicator.IsVisible = true; this.ActivityIndicator.IsRunning = true; string username = this.EntryUsername.Text.Trim(); string password = this.EntryPassword.Text.Trim(); string email = this.EntryEmail.Text.Trim(); // Connect to the server in a background task and await a response. OperationReturnMessage response = await Task.Run(() => ServerOperations.RegisterAccount(username, password, email)); if (response != OperationReturnMessage.FalseFailedConnection) { if (response == OperationReturnMessage.TrueConfirmEmail) { this.LabelMessage.Text = "Account successfully created."; this.username = username; this.password = password; var confirmationPage = new EmailConfirmationPage(username, password); confirmationPage.EmailConfirmed += this.OnEmailConfirmed; confirmationPage.ConfirmLaterSelected += this.OnConfirmLaterSelected; await this.Navigation.PushModalAsync(confirmationPage); } else if (response == OperationReturnMessage.FalseUsernameAlreadyExists) { this.LabelMessage.Text = $"Account could not be created - Username already exists."; } else if (response == OperationReturnMessage.FalseInvalidEmail) { this.LabelMessage.Text = $"Account could not be created - Invalid Email."; } else { this.LabelMessage.Text = $"Account could not be created."; } } else { this.LabelMessage.Text = "Connection failed: Please try again."; } this.ButtonCreateAccount.IsEnabled = true; this.EntryEmail.IsEnabled = true; this.EntryPassword.IsEnabled = true; this.EntryUsername.IsEnabled = true; this.ActivityIndicator.IsVisible = false; this.ActivityIndicator.IsRunning = false; }
/// <summary> /// Change the password of the user. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonChangePassword_Clicked(object sender, EventArgs e) { if (this.SetupFrameBegin(this.FrameChangePassword, this.StackLayoutChangePasswordContent)) { string oldPassword = this.EntryCurrentPasswordChangePassword.Text.Trim(); string newPassword = this.EntryNewPasswordChangePassword.Text.Trim(); string newPasswordReenter = this.EntryReenterNewPasswordChangePassword.Text.Trim(); if (newPassword == newPasswordReenter) { if (!(newPassword.Length < 8 || newPassword.Length > 16)) { if (!(newPassword.Contains(" ") || newPassword.Contains(".") || newPassword.Contains("/") || newPassword.Contains("`"))) { OperationReturnMessage message = await Task.Run(() => this.ChangePassword(oldPassword, newPassword)); if (message == OperationReturnMessage.True) { this.LabelChangePasswordMessage.Text = "Password changed successfully."; await CredentialManager.SaveCredentialAsync(CredentialManager.Username, newPassword, CredentialManager.EmailConfirmed); } else if (message == OperationReturnMessage.FalseInvalidCredentials) { this.LabelChangePasswordMessage.Text = "Incorrect current password."; } else if (message == OperationReturnMessage.FalseNoConnection) { this.LabelDeleteAccountMessage.Text = "Failed to connect to server. Please try again."; } else { this.LabelChangePasswordMessage.Text = "Password change failed - Please try again."; } } else { this.LabelChangePasswordMessage.Text = "New password must not contain empty space, \'.\', \'/\', or \'`\'"; } } else { this.LabelChangePasswordMessage.Text = "New password must be greater than 8 characters and less than 16 characters long."; } } else { this.LabelChangePasswordMessage.Text = "New passwords do not match."; } } this.SetupFrameEnd(this.StackLayoutChangePasswordContent); }
/// <summary> /// when the login button is clicked, attempt to login /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonLogin_Clicked(object sender, EventArgs e) { this.LabelMessage.Text = ""; this.ButtonLogin.IsEnabled = false; this.ButtonToCreateAccountPage.IsEnabled = false; string username = this.EntryUsername.Text.Trim(); string password = this.EntryPassword.Text; this.ActivityIndicator.IsVisible = true; this.ActivityIndicator.IsRunning = true; OperationReturnMessage response = await Task.Run(() => ServerOperations.LoginAccount(username, password)); if (response != OperationReturnMessage.FalseFailedConnection) { if (response == OperationReturnMessage.True) { await CredentialManager.SaveCredentialAsync(username, password, true); this.OnLoggedIn(); } else if (response == OperationReturnMessage.TrueConfirmEmail) { var confirmationPage = new EmailConfirmationPage(username, password); confirmationPage.EmailConfirmed += this.OnEmailConfirmed; await this.Navigation.PushModalAsync(confirmationPage); await CredentialManager.SaveCredentialAsync(username, password, false); this.OnLoggedIn(); } else if (response == OperationReturnMessage.FalseInvalidCredentials) { this.LabelMessage.Text = "Login Failed - Username and/or Password are Incorrect."; } else { this.LabelMessage.Text = "Login Failed."; } } else { this.LabelMessage.Text = "Connection failed: Please try again."; } this.ButtonToCreateAccountPage.IsEnabled = true; this.ActivityIndicator.IsRunning = false; this.ActivityIndicator.IsVisible = false; this.EntryPassword.Text = ""; this.ButtonLogin.IsEnabled = true; }
/// <summary> /// Check if the current user credentials are valid with the server or not /// in a background task. /// </summary> /// <returns>The OperationReturnMessage from the server.</returns> public static async Task <OperationReturnMessage> CheckLoginStatusAsync() { string username = await SecureStorage.GetAsync("username"); Username = username; if (CrossConnectivity.Current.IsConnected) { if ((username != null) && (username != "")) { OperationReturnMessage message = ServerOperations.LoginAccount(username, await SecureStorage.GetAsync("password")); if (message != OperationReturnMessage.FalseFailedConnection) { if (message == OperationReturnMessage.True) { IsLoggedIn = true; EmailConfirmed = true; } else if (message == OperationReturnMessage.TrueConfirmEmail) { IsLoggedIn = true; EmailConfirmed = false; } else { IsLoggedIn = false; EmailConfirmed = false; Username = "******"; await SecureStorage.SetAsync("password", ""); } return(message); } else { return(CannotConnectToServer(username)); } } else { Username = "******"; IsLoggedIn = false; EmailConfirmed = false; Username = "******"; return(OperationReturnMessage.False); } } else // If the user is offline { return(CannotConnectToServer(username)); } }
/// <summary> /// When a user wants to unsubscribe from a quiz /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ImageButtonUnsubscribe_Clicked(object sender, EventArgs e) { if (CredentialManager.IsLoggedIn) { ImageButton button = (sender as ImageButton); string dbId = button.StyleId; bool answer = await this.DisplayAlert("Are you sure you want to unsubscribe?", "You will no longer get updates of this quiz", "Yes", "No"); if (answer) { ActivityIndicator indicatorSyncing = (button.Parent as StackLayout).Children[(int)SubscribeUtils.SubscribeType.Syncing] as ActivityIndicator; button.IsVisible = false; indicatorSyncing.IsVisible = true; indicatorSyncing.IsRunning = true; // get rosterInfo QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(dbId); // tell the roster that the quiz is deleted QuizInfo rosterInfoUpdated = new QuizInfo(rosterInfo) { IsDeletedLocally = true, LastModifiedDate = DateTime.Now.ToString() }; QuizRosterDatabase.EditQuizInfo(rosterInfoUpdated); OperationReturnMessage returnMessage = await SubscribeUtils.UnsubscribeFromQuizAsync(dbId); if (returnMessage == OperationReturnMessage.True) { (button.Parent as StackLayout).Children[(int)SubscribeUtils.SubscribeType.Subscribe].IsVisible = true; // add in subscribe button QuizRosterDatabase.DeleteQuizInfo(dbId); } else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials) { button.IsVisible = true; await this.DisplayAlert("Invalid Credentials", "Your current login credentials are invalid. Please log in and try again.", "OK"); } else { button.IsVisible = true; await this.DisplayAlert("Unsubscribe Failed", "The unsubscription request could not be completed. Please try again.", "OK"); } indicatorSyncing.IsVisible = false; indicatorSyncing.IsRunning = false; } } else { await this.DisplayAlert("Hold on!", "Before you can subscribe to any quizzes, you have to login.", "Ok"); } }
/// <summary> /// Deletes the quiz from the roster /// </summary> private async Task ButtonDelete_Clicked(string DBId) { bool answer = await this.DisplayAlert("Are you sure you want to delete this quiz?", "This will delete the copy on your device and in the cloud. This is not reversable.", "Yes", "No"); if (answer) { // Acquire QuizInfo from roster QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(DBId); string path = rosterInfo.RelativePath; if (rosterInfo != null) { string dbId = rosterInfo.DBId; // tell the roster that the quiz is deleted QuizInfo rosterInfoUpdated = new QuizInfo(rosterInfo) { IsDeletedLocally = true, LastModifiedDate = DateTime.Now.ToString() }; QuizRosterDatabase.EditQuizInfo(rosterInfoUpdated); // If connected, tell server to delete this quiz If not, it will tell server to delete next time it is connected in QuizRosterDatabase.UpdateLocalDatabase() OperationReturnMessage returnMessage = await ServerOperations.DeleteQuiz(dbId); if (returnMessage == OperationReturnMessage.True) { QuizRosterDatabase.DeleteQuizInfo(dbId); } if (System.IO.Directory.Exists(path)) { Directory.Delete(path, true); } this.QuizNumber.Text = "You have published a total of " + await Task.Run(() => ServerOperations.GetNumberOfQuizzesByAuthorName(CredentialManager.Username)) + " quizzes!"; } else { await DisplayAlert("Could not delete quiz", "This quiz could not be deleted at this time. Please try again later", "OK"); } // Setup Page again after deletion await this.UpdateProfilePageAsync(); } }
/// <summary> /// when the button is clicked, either confirms the email and disappears or informs the user of a mistake /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonConfirmEmail_Clicked(object sender, EventArgs e) { OperationReturnMessage result = await Task.Run(() => ServerOperations.ConfirmEmail(this.username, this.EntryConfirmationCode.Text.Trim())); if (result == OperationReturnMessage.True) { this.emailConfirmed = true; await this.Navigation.PopModalAsync(true); } else { this.LabelMessage.Text = "Email could not be confirmed. Please try your code again."; } }
/// <summary> /// When the button to use a different email is clicked, changes the email to that one /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ButtonFixEmail_Clicked(object sender, EventArgs e) { string newEmail = this.EntryChangeEmail.Text.Trim(); OperationReturnMessage result = await Task.Run(() => ServerOperations.ChangeEmail(this.username, this.password, newEmail)); if (result == OperationReturnMessage.TrueConfirmEmail) { this.LabelTitle.Text = $"Enter the confirmation code sent to {newEmail}"; } else { this.LabelMessage.Text = $"Email could not be changed."; } }
/// <summary> /// Receive an OperationReturnMessage from the server after sending a server request. /// </summary> /// <param name="toSend">The data to send to server.</param> /// <returns>The OperationReturnMessage returned by the server after data has been received /// and processed by the server.</returns> private static OperationReturnMessage ReceiveFromServerORM(byte[] toSend) { if (CrossConnectivity.Current.IsConnected) { byte[] data = ServerConnector.SendByteArray(toSend); if (data.Length > 0) { OperationReturnMessage message = (OperationReturnMessage)(data[0]); return(message); } else { return(OperationReturnMessage.FalseFailedConnection); } } else { return(OperationReturnMessage.FalseNoConnection); } }
/// <summary> /// Subscribes to a quiz given the ID /// </summary> /// <param name="dbId">the ID of the quiz to sub to</param> /// <param name="quizzesSearched">the quizzes currently displayed (used to get info about the quiz from the dbid)</param> /// <returns>If the subscription was successful</returns> public static async Task <OperationReturnMessage> SubscribeToQuizAsync(string dbId, List <QuizInfo> quizzesSearched) { if (QuizRosterDatabase.GetQuizInfo(dbId) == null) // make sure it isn't in yet { OperationReturnMessage returnMessage = await Task.Run(async() => await ServerOperations.SubscribeToQuiz(dbId)); if (returnMessage == OperationReturnMessage.True) { QuizInfo quiz = quizzesSearched.Where(quizInfo => quizInfo.DBId == dbId).First(); string lastModifiedDate = await Task.Run(() => ServerOperations.GetLastModifiedDate(dbId)); QuizInfo newInfo = new QuizInfo { DBId = quiz.DBId, AuthorName = quiz.AuthorName, QuizName = quiz.QuizName, Category = quiz.Category, LastModifiedDate = lastModifiedDate, SyncStatus = (int)SyncStatusEnum.NotDownloadedAndNeedDownload // 4 to represent not present in local directory and need download }; QuizRosterDatabase.SaveQuizInfo(newInfo); return(returnMessage); } else if (returnMessage == OperationReturnMessage.FalseInvalidCredentials) { CredentialManager.IsLoggedIn = false; return(returnMessage); } else { return(returnMessage); } } else { return(OperationReturnMessage.False); } }