/// <summary> /// Aktualisiert die lokal gespeicherten Datensätze der übergebenen Abstimmung. /// Gibt an, ob die Aktualisierung erfolgreich war, oder ob fehlende Referenzen (z.B. /// der lokale Datensatz des Administrators) eine Aktualisierung verhindert haben. /// Methode aktualisisert nur die Abstimmungsdaten selbst, Subressourcen werden nicht aktualisiert, /// d.h. keine Optionen und Abstimmungsergebnisse werden aktualisiert. /// </summary> /// <param name="newBallot">Das Objekt mit den neuen Abstimmungsdaten.</param> /// <returns>Liefert true, wenn die Aktualisierung erfolgreich war, false, wenn die /// Aktualisierung aufgrund fehlender Referenzen nicht durchgeführt werden konnte.</returns> /// <exception cref="ClientException">Wirft ClientException, wenn Aktualisierung fehlgeschlagen ist.</exception> public bool UpdateBallot(Ballot newBallot) { bool updatedSuccessfully = false; try { if (newBallot != null && userController.IsUserLocallyStored(newBallot.AdminId) && groupDBManager.IsBallotStored(newBallot.Id)) { groupDBManager.UpdateBallot(newBallot); updatedSuccessfully = true; } } catch (DatabaseException ex) { Debug.WriteLine("UpdateBallot: Failed to update ballot with id {0} in local datasets.", newBallot.Id); throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message); } return updatedSuccessfully; }
/// <summary> /// Erzeugt ein Objekt vom Typ Ballot, welches die vom Nutzer eingegebenen Daten beinhaltet. /// </summary> /// <returns>Ein Objekt vom Typ Ballot.</returns> private Ballot generateBallotObjectFromEnteredData() { Ballot ballot = new Ballot(); ballot.Title = EnteredTitle; ballot.Description = EnteredDescription; ballot.IsMultipleChoice = IsMultipleChoiceSelected; ballot.HasPublicVotes = IsPublicVotesSelected; ballot.IsClosed = IsClosedSelected; ballot.AdminId = groupController.GetLocalUser().Id; if (BallotOptionsCollection != null) { ballot.Options = new List<Option>(); foreach (Option option in BallotOptionsCollection) { ballot.Options.Add(option); } } return ballot; }
/// <summary> /// Speichert die Abstimmung in den lokalen Datensätzen ab. /// </summary> /// <param name="groupId">Die Id der Gruppe, der die Abstimmung zugeordnet ist.</param> /// <param name="ballot">Die zu speichernde Abstimmung in Form eines Ballot Objekts.</param> /// <returns>Liefert true, falls Speicherung erfolgreich, liefert false, falls Speicherung aufgrund fehlender /// Referenzen (z.B. fehlender Nutzerdatensatz in der Datenbank) nicht ausgeführt werden konnte.</returns> /// <exception cref="ClientException">Wirft ClientException, wenn bei der Speicherung ein unerwarteter Fehler auftritt.</exception> public bool StoreBallot(int groupId, Ballot ballot) { bool insertedSuccessfully = false; bool fulfillsConstraints = true; try { if (groupDBManager.IsGroupStored(groupId) && !groupDBManager.IsBallotStored(ballot.Id)) { if (!userController.IsUserLocallyStored(ballot.AdminId)) { Debug.WriteLine("StoreBallot: The ballot's admin (id: {0}) is not locally stored. Cannot continue.", ballot.AdminId); fulfillsConstraints = false; } if (ballot.Options != null) { Dictionary<int, bool> userStoredStatus = new Dictionary<int, bool>(); foreach (Option option in ballot.Options) { // Falls Voter gesetzt, so müssen diese geprüft werden. if (option.VoterIds != null) { foreach (int voter in option.VoterIds) { if (!userStoredStatus.ContainsKey(voter)) { userStoredStatus.Add(voter, userController.IsUserLocallyStored(voter)); } } } } // Prüfe, ob alle Bedingungen für Insert erfüllt sind. foreach (bool status in userStoredStatus.Values) { if (!status) { Debug.WriteLine("StoreBallot: There are missing users. Cannot insert ballot."); fulfillsConstraints = false; } } } if (fulfillsConstraints) { // Speichere Abstimmung ab. groupDBManager.StoreBallot(groupId, ballot); insertedSuccessfully = true; } } else { if (groupDBManager.IsBallotStored(ballot.Id)) { Debug.WriteLine("StoreBallot: Ballot is already stored."); return true; } else { Debug.WriteLine("StoreBallot: Cannot store without corresponding group."); } } } catch (DatabaseException ex) { Debug.WriteLine("StoreBallot: Storing failed. Message is {0}.", ex.Message); throw new ClientException(ErrorCodes.LocalDatabaseException, ex.Message); } Debug.WriteLine("StoreBallot: Returns {0}.", insertedSuccessfully); return insertedSuccessfully; }
/// <summary> /// Bereitet ein Objekt vom Typ Ballot vor, welches alle Properties enthält, die sich geändert haben. /// Die Methode bekommt eine alte Version eines Ballot Objekts und eine neue Version und ermittelt /// dann die Properties, die eine Aktualisierung erhalten haben und schreibt diese in eine neue Ballot /// Instanz. Die von der Methode zurückgelieferte Ballot Instanz kann dann direkt für die Aktualisierung auf /// dem Server verwendet werden. Achtung: Hat sich überhaupt keine Property geändert, so gibt die Methode null zurück. /// </summary> /// <param name="oldBallot">Das Ballot Objekt vor der Aktualisierung.</param> /// <param name="newBallot">Das Ballot Objekt mit den aktuellen Werten.</param> /// <returns>Ein Objekt der Klasse Ballot, bei dem nur die Eigenschaften mit neuem Wert gesetzt sind. /// Hat sich keine Eigenschaft geändert, so wird null zurückgegeben.</returns> private Ballot perpareUpdatableBallotInstance(Ballot oldBallot, Ballot newBallot) { bool hasChanged = false; Ballot updatedBallot = new Ballot(); if (oldBallot.Title != newBallot.Title) { hasChanged = true; updatedBallot.Title = newBallot.Title; } if (oldBallot.Description != newBallot.Description) { hasChanged = true; updatedBallot.Description = newBallot.Description; } if (oldBallot.IsClosed.HasValue && newBallot.IsClosed.HasValue && oldBallot.IsClosed.Value != newBallot.IsClosed.Value) { hasChanged = true; updatedBallot.IsClosed = newBallot.IsClosed; } // Prüfe, ob sich überhaupt eine Property geändert hat. if (!hasChanged) { Debug.WriteLine("perpareUpdatableBallotInstance: No property of ballot has changed. Method will return null."); updatedBallot = null; } return updatedBallot; }
/// <summary> /// Führt Aktualisierung der Abstimmung aus. Es wird ermittelt welche Eigenschaften eine Aktualisierung /// erhalten haben. Die Aktualisierungen werden an den Server übermittelt, der die Aktualisierung auf /// dem Serverdatensatz ausführt und die Gruppenmitglieder über die Änderung informiert. /// Ebenso werden die Abstimmungsoptionen aktualisiert, falls Änderungen vorgenommen wurden. /// </summary> /// <param name="groupId">Die Id der Gruppe, zu der die Abstimmung gehört.</param> /// <param name="oldBallot">Der Datensatz der Abstimmung, vor der Aktualisierung.</param> /// <param name="newBallot">Der Datensatz mit den neu eingegebenen Daten. Enthält auch die festgelegten /// Abstimmungsoptionen.</param> /// <returns>Liefert true, wenn die Aktualisierung erfolgreich war, ansonsten false.</returns> /// <exception cref="ClientException">Wirft ClientException, wenn Aktualisierung fehlgeschlagen ist, oder nur /// in Teilen erfolgreich durchgeführt werden konnte.</exception> public async Task<bool> EditBallotAsync(int groupId, Ballot oldBallot, Ballot newBallot) { if (oldBallot == null || newBallot == null) return false; // Validiere zunächst die neu eingegebenen Daten. Bei Validierungsfehlern kann man hier gleich abbrechen. clearValidationErrors(); newBallot.ClearValidationErrors(); newBallot.ValidateAll(); if (newBallot.HasValidationErrors()) { reportValidationErrors(newBallot.GetValidationErrors()); return false; } // Generiere Ballot Objekt für die Aktualisierung. Dieses Objekt enthält nur die aktualisierten Eigenschaften. bool requiresUpdate = true; Ballot updatableBallot = perpareUpdatableBallotInstance(oldBallot, newBallot); if (updatableBallot == null) { Debug.WriteLine("EditBallotAsync: No update required."); requiresUpdate = false; } if (requiresUpdate) { // Erstelle JSON-Dokument für die Aktualisierung. string jsonContent = jsonParser.ParseBallotToJson(updatableBallot); if (jsonContent == null) { Debug.WriteLine("EditBallotAsync: Failed to generate json document."); throw new ClientException(ErrorCodes.JsonParserError, "Failed to generate json document."); } // Setze Request zur Aktualisierung der Abstimmung ab. string serverResponse = null; try { serverResponse = await groupAPI.SendUpdateBallotRequest( getLocalUser().ServerAccessToken, groupId, oldBallot.Id, jsonContent); } catch (APIException ex) { Debug.WriteLine("EditBallotAsync: Failed request. Error code: {0}, msg is: '{1}'.", ex.ErrorCode, ex.Message); handleGroupRelatedErrors(ex.ErrorCode, groupId, null, oldBallot.Id); throw new ClientException(ex.ErrorCode, ex.Message); } // Parse Antwort des Servers. Ballot serverBallot = jsonParser.ParseBallotFromJson(serverResponse); if (serverBallot != null) { Debug.WriteLine("EditBallotAsync: Start local updating of ballot."); // Aktualisiere die Abstimmung. bool successful = UpdateBallot(serverBallot); if (!successful) { throw new ClientException(ErrorCodes.LocalDatabaseException, "Failed to update local ballot"); } } else { throw new ClientException(ErrorCodes.JsonParserError, "Failed to parse server response"); } } // Führe noch eine Aktualisierung der Abstimmungsoptionen durch. List<Option> currentOptions = GetOptions(oldBallot.Id, false); // Extrahiere die Liste von Abstimmungsoptionen der neuen Abstimmung. List<Option> newOptionList = newBallot.Options; await SynchronizeBallotOptionsAsync(groupId, oldBallot.Id, currentOptions, newOptionList); return true; }
/// <summary> /// Sendet einen Request zum Anlegen einer neuen Abstimmung an den Server. /// </summary> /// <param name="groupId">Die Id der Gruppe, in der die Abstimmung angelegt werden soll.</param> /// <param name="newBallot">Das Abstimmungsojekt mit den Daten der neuen Abstimmung.</param> /// <returns>Liefert true, wenn die Abstimmung erfolgreich angelegt werden konnte. Liefert false, /// wenn die Abstimmung nicht angelegt werden konnte, da z.B. die Validierung der Daten fehlgeschlagen ist.</returns> /// <exception cref="ClientException">Wirft ClientException, wenn Erzeugung der Abstimmung fehlgeschlagen ist, oder /// vom Server abgelehnt wurde.</exception> public async Task<bool> CreateBallotAsync(int groupId, Ballot newBallot) { bool successful = false; if (newBallot == null) return successful; // Führe Validierung der Abstimmungsdaten durch. Abbruch bei aufgetretenem Validierungsfehler. clearValidationErrors(); newBallot.ClearValidationErrors(); newBallot.ValidateAll(); if (newBallot.HasValidationErrors()) { reportValidationErrors(newBallot.GetValidationErrors()); return successful; } // Die für die neue Abstimmung angegebenen Optionen. List<Option> ballotOptions = newBallot.Options; // Setze Optionen im Objekt selbst auf null zwecks Create Request. newBallot.Options = null; // Generiere JSON-Dokument. string jsonContent = jsonParser.ParseBallotToJson(newBallot); if (jsonContent == null) { Debug.WriteLine("CreateBallotAsync: Couldn't serialize ballot object to json. Cannot continue."); throw new ClientException(ErrorCodes.JsonParserError, "Failed to generate json document."); } // Setze Request zum Anlegen der Abstimmung ab. string serverResponse = null; try { serverResponse = await groupAPI.SendCreateBallotRequest( getLocalUser().ServerAccessToken, groupId, jsonContent); successful = true; } catch (APIException ex) { Debug.WriteLine("CreateBallotAsync: Request failed. Error code is: {0}.", ex.ErrorCode); handleGroupRelatedErrors(ex.ErrorCode, groupId, null, null); throw new ClientException(ex.ErrorCode, ex.Message); } Ballot serverBallot = null; if (serverResponse != null) { // Parse Server Antwort. serverBallot = jsonParser.ParseBallotFromJson(serverResponse); if (serverBallot != null) { // Speichere Abstimmung ab. if (!StoreBallot(groupId, serverBallot)) { Debug.WriteLine("CreateBallotAsync: Failed to store ballot."); throw new ClientException(ErrorCodes.LocalDatabaseException, "Failed to store ballot with id " + serverBallot.Id + "."); } } else { throw new ClientException(ErrorCodes.JsonParserError, "Failed to parse server response."); } } // Sende noch die Requests zum Anlegen der Abstimmungsoptionen. if (serverBallot != null && ballotOptions != null) { bool successfullyCreatedOptions = true; foreach (Option option in ballotOptions) { try { await CreateBallotOptionAsync(groupId, serverBallot.Id, option); } catch (ClientException ex) { // Nicht die ganze Ausführung abbrechen bei fehlgeschlagenem Request. // Versuche den Rest der Optionen dennoch erfolgreich anzulegen. Debug.WriteLine("CreateBallotAsync: Failed to store a ballot option. " + "The option with id {0} could not be created. Msg is: {1}.", option.Id, ex.Message); successfullyCreatedOptions = false; } } if (!successfullyCreatedOptions) { // Werfe Fehler mit entsprechendem Fehlercode. Hinweis, dass nicht alle Optionen angelegt wurden. throw new ClientException(ErrorCodes.OptionCreationHasFailedInBallotCreationProcess, "Failed to store options."); } } return successful; }
/// <summary> /// Wandelt ein übergebenes Objekt vom Typ Ballot in ein JSON-Dokument um. /// </summary> /// <param name="ballot">Das Abstimmungsobjekt (Typ Ballot), das umgewandelt werden soll.</param> /// <returns>Das erstellte JSON-Dokument, oder null, falls die Umwandung fehlgeschlagen ist.</returns> public string ParseBallotToJson(Ballot ballot) { string jsonContent = null; try { jsonContent = JsonConvert.SerializeObject(ballot); } catch (JsonException ex) { Debug.WriteLine("ParseBallotToJson: Json parser error occurred. " + "Message is {0}.", ex.Message); } return jsonContent; }