/// <summary> /// Handle event when user clicks delete quiz button. /// </summary> /// <param name="e"></param> private async void ButtonDelete_Clicked(string deleteType, string DBId) { if (CredentialManager.IsLoggedIn) { bool unsubscribe = deleteType == "Unsubscribe"; string question; string message; if (unsubscribe) { question = "Are you sure you want to unsubscribe?"; message = "This will remove the copy from your device"; } else { question = "Are you sure you want to delete this quiz?"; message = "This will delete the copy on your device and in the cloud. This is not reversable."; } bool answer = await this.DisplayAlert(question, message, "Yes", "No"); if (answer) { // Acquire QuizInfo from roster QuizInfo rosterInfo = QuizRosterDatabase.GetQuizInfo(DBId); // Author string path = rosterInfo.RelativePath; // 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() if (CrossConnectivity.Current.IsConnected) { OperationReturnMessage returnMessage; if (unsubscribe) { returnMessage = await SubscribeUtils.UnsubscribeFromQuizAsync(DBId); } else { returnMessage = await ServerOperations.DeleteQuiz(DBId); } if (System.IO.Directory.Exists(path)) { Directory.Delete(path, true); } this.Setup(); } } } else { await this.DisplayAlert("Hold on!", "You must be create an account or log in before you can unsubscribe", "OK"); } }
/// <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> /// 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> /// Saves updates to a quizInfo /// </summary> /// <param name="editedQuizInfo">the new version of the quizinfo to save</param> public void EditQuizInfo(QuizInfo editedQuizInfo) { Realm realmDB = Realm.GetInstance(App.realmConfiguration(this.dbPath)); realmDB.Write(() => { realmDB.Add(editedQuizInfo, update: true); }); QuizInfo rosterCopy = new QuizInfo(editedQuizInfo) { SyncStatus = (int)SyncStatusEnum.NeedUpload // Default to 1, meaning "needs upload" in roster }; QuizRosterDatabase.EditQuizInfo(rosterCopy); }
/// <summary> /// Download a quiz from the server. /// </summary> /// <param name="dBId">The DBId of the quiz to download</param> /// <param name="category">The category the quiz belongs in.</param> /// <returns></returns> public static bool GetQuiz(string dBId, string category) { // TO DO: CHECK IF quizName or category changed and save accordingly string tempPath = App.UserPath + "/" + "temp" + "/" + dBId + "/"; string tempFilePath = tempPath + "/" + realmFileExtension; // Store the realm file into a temporary directory in order the retrieve information from it // (Information regarding the images in order to retrieve them from the server) Directory.CreateDirectory(tempPath); byte[] realmFile = (byte[])SendStringData($"{dBId}/-", ServerRequestTypes.GetRealmFile); if (realmFile.Length > 0) { File.WriteAllBytes(tempFilePath, realmFile); } else { return(false); } // Retrieve info regarding the images from the realm file from its temporary location Realm realmDB = Realm.GetInstance(App.realmConfiguration(tempFilePath)); IQueryable <Question> questionsWithPictures = realmDB.All <Question>().Where(question => question.NeedsPicture); foreach (Question question in questionsWithPictures) { byte[] jpegFile = (byte[])SendStringData($"{question.QuestionId}/{dBId}/-", ServerRequestTypes.GetJPEGImage); string jpegFilePath = tempPath + "/" + question.QuestionId + jpegFileExtension; if (jpegFile.Length > 0) { File.WriteAllBytes(jpegFilePath, jpegFile); } else { return(false); } } QuizInfo info = realmDB.All <QuizInfo>().First(); string newQuizName = info.QuizName; string newCategory = info.Category; string newLastModfiedDate = info.LastModifiedDate; string quizPath = info.RelativePath; string realmFilePath = quizPath + "/" + info.DBId + realmFileExtension; Directory.CreateDirectory(quizPath); string[] imageFilePaths = Directory.GetFiles(tempPath, "*.jpg"); string[] realmFilePaths = Directory.GetFiles(tempPath, "*.realm"); foreach (string path in realmFilePaths) { File.Copy(path, quizPath + "/" + info.DBId + realmFileExtension, true); } foreach (string path in imageFilePaths) { string imageName = path.Split('/').Last(); File.Copy(path, quizPath + "/" + imageName, true); } if (category != newCategory) { DeleteDirectory(info.RelativePath, true); } DeleteDirectory(tempPath, true); QuizInfo infoCopy = new QuizInfo(QuizRosterDatabase.GetQuizInfo(dBId)) { SyncStatus = (int)SyncStatusEnum.Synced, QuizName = newQuizName, Category = newCategory, LastModifiedDate = newLastModfiedDate }; QuizRosterDatabase.EditQuizInfo(infoCopy); return(true); }