486 lines
20 KiB
C#
486 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using gehGassi.Dto.Common;
|
|
using gehGassi.Dto;
|
|
using gehGassiApp.Core.Data;
|
|
using gehGassiApp.Core.Interfaces;
|
|
using gehGassiApp.Core.Interfaces.Synchronization;
|
|
using gehGassiApp.Core.Mapper;
|
|
using gehGassiApp.Core.Resources;
|
|
using gehGassiApp.Domain.Common;
|
|
using gehGassiApp.Domain.Favourites;
|
|
using gehGassiApp.Domain.Users;
|
|
using gehGassi.Dto.Favourites;
|
|
|
|
namespace gehGassiApp.Core.Services
|
|
{
|
|
/// <summary>
|
|
/// Service der die Verwaltung von Favoriten ermöglicht
|
|
/// </summary>
|
|
public class FavouriteService : ServiceBase<Favourite>, IFavouriteService
|
|
{
|
|
private readonly ICommunicationService _communicationService;
|
|
private readonly ISyncInfoPullService _pullService;
|
|
private readonly ISyncInfoPushService _pushService;
|
|
private readonly ILocationService _locationService;
|
|
|
|
private readonly IRepository<AppUser> _appUserRepository;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="unitOfWork">Instanz eines IUnitOfWork</param>
|
|
/// <param name="communicationService">Instanz eines ICommunicationService</param>
|
|
/// <param name="syncInfoPullService">Instanz eines ISyncInfoPullService</param>
|
|
/// <param name="syncInfoPushService">Instanz eines ISyncInfoPushService</param>
|
|
/// <param name="locationService">Instanz eines ILocationService</param>
|
|
public FavouriteService(IUnitOfWork unitOfWork, ICommunicationService communicationService, ISyncInfoPullService syncInfoPullService, ISyncInfoPushService syncInfoPushService, ILocationService locationService) : base(unitOfWork)
|
|
{
|
|
_communicationService = communicationService;
|
|
_pullService = syncInfoPullService;
|
|
_pushService = syncInfoPushService;
|
|
_locationService = locationService;
|
|
|
|
_appUserRepository = unitOfWork.GetRepository<AppUser>();
|
|
}
|
|
|
|
public override Favourite Get(object id, bool noTracking = true)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override async Task<Favourite> GetAsync(object id, bool noTracking = true)
|
|
{
|
|
await Task.Delay(1);
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erstellen eines Favoriten
|
|
/// </summary>
|
|
/// <returns>Favourite</returns>
|
|
public Favourite Create()
|
|
{
|
|
var favourite = new Favourite()
|
|
{
|
|
Id = Guid.NewGuid().ToString("N"),
|
|
Created = DateTimeOffset.UtcNow
|
|
};
|
|
return favourite;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hinzufügen eines Favoriten
|
|
/// </summary>
|
|
/// <param name="favourite">Favourite</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Angelegter Favorit</returns>
|
|
public async Task<Favourite> AddAsync(Favourite favourite, string accessToken, CancellationToken token)
|
|
{
|
|
var existingFavourite = await Repository.GetAsync(favourite.Id);
|
|
if (existingFavourite == null)
|
|
{
|
|
Repository.Add(favourite);
|
|
await CommitAsync();
|
|
|
|
//Jetzt das Rating an der Server übertragen oder ein Delta erstellen
|
|
|
|
var dto = favourite.ToDto();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
var createDelta = true;
|
|
if (isConnected)
|
|
{
|
|
var createResult = await _communicationService.CreateFavouriteAsync(dto, accessToken, token);
|
|
if (createResult.Success && createResult.Value.Status != CreateStatus.Error)
|
|
{
|
|
createDelta = false;
|
|
}
|
|
}
|
|
|
|
if (createDelta)
|
|
{
|
|
await _pushService.AddAsync(nameof(Favourite), favourite.Id, SyncOperation.Create, favourite).ConfigureAwait(false);
|
|
}
|
|
return favourite;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aktualisieren eines Favoriten
|
|
/// </summary>
|
|
/// <param name="favourite">Favourite</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>true wenn erfolgreich, false sonst</returns>
|
|
public async Task<bool> UpdateAsync(Favourite favourite, string accessToken, CancellationToken token)
|
|
{
|
|
var localFavourite = await Repository.FirstOrDefaultAsync(c => c.Id == favourite.Id, false).ConfigureAwait(false);
|
|
if (localFavourite != null && !localFavourite.Deleted)
|
|
{
|
|
localFavourite.AppUserId = favourite.AppUserId;
|
|
localFavourite.Table = favourite.Table;
|
|
localFavourite.Key = favourite.Key;
|
|
localFavourite.UpdatedAt = DateTimeOffset.UtcNow;
|
|
|
|
Repository.Update(localFavourite);
|
|
await CommitAsync().ConfigureAwait(false);
|
|
|
|
var dto = localFavourite.ToDto();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
var createDelta = true;
|
|
if (isConnected)
|
|
{
|
|
var updateResult = await _communicationService.UpdateFavouriteAsync(dto, accessToken, token);
|
|
if (updateResult.Success && updateResult.Value)
|
|
createDelta = false;
|
|
}
|
|
|
|
if (createDelta)
|
|
{
|
|
await _pushService.AddAsync(nameof(Favourite), localFavourite.Id, SyncOperation.Edit, localFavourite).ConfigureAwait(false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Echtes Löschen eines Favoriten
|
|
/// </summary>
|
|
/// <param name="favouriteId">Id des Favoriten</param>
|
|
/// <param name="appUserId">Id des AppBenutzers</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>true wenn erfolgreich, false sonst</returns>
|
|
public async Task<bool> DeleteAsync(string favouriteId, string appUserId, string accessToken, CancellationToken token)
|
|
{
|
|
var localFavourite = await Repository.FirstOrDefaultAsync(c => c.Id == favouriteId, false).ConfigureAwait(false);
|
|
if (localFavourite != null && localFavourite.AppUserId == appUserId)
|
|
{
|
|
Repository.Remove(localFavourite);
|
|
await CommitAsync().ConfigureAwait(false);
|
|
|
|
var dto = localFavourite.ToDto();
|
|
var isConnected = await _communicationService.IsConnected();
|
|
var createDelta = true;
|
|
if (isConnected)
|
|
{
|
|
var deleteResult = await _communicationService.DeleteFavouriteAsync(dto, appUserId, accessToken, token);
|
|
if (deleteResult.Success && deleteResult.Value)
|
|
createDelta = false;
|
|
}
|
|
|
|
if (createDelta)
|
|
{
|
|
await _pushService.AddAsync(nameof(Favourite), localFavourite.Id, SyncOperation.Delete, localFavourite).ConfigureAwait(false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prüfen ob ein Objekt ein Favorit ist. Prüft nur Lokal!
|
|
/// </summary>
|
|
/// <param name="key">Id des Objekts</param>
|
|
/// <param name="table">Typ des Objekts</param>
|
|
/// <returns>true wenn ein Favorit, false sonst</returns>
|
|
public async Task<bool> IsFavouriteLocalAsync(string key, string table)
|
|
{
|
|
var existing = await Repository.FirstOrDefaultAsync(c => c.Key == key && c.Table == table && c.Deleted == false);
|
|
return existing != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Toggeln des Favoriten-Status eines Objektes.
|
|
/// Entweder wird der Favorit angelegt, oder gelöscht
|
|
/// </summary>
|
|
/// <param name="key">Id des Objekts</param>
|
|
/// <param name="table">Typ des Objekts</param>
|
|
/// <param name="appUserId">Id des AppUsers</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>true wenn erfolgreich, false sonst</returns>
|
|
public async Task<bool> ToggleAsync(string key, string table, string appUserId, string accessToken, CancellationToken token)
|
|
{
|
|
var existing = await Repository.FirstOrDefaultAsync(c => c.Key == key && c.Table == table && c.Deleted == false);
|
|
if (existing != null)
|
|
{
|
|
//Favorit existiert, also löschen
|
|
return await DeleteAsync(existing.Id, appUserId, accessToken, token);
|
|
}
|
|
else
|
|
{
|
|
//Favorit existiert nicht, also anlegen
|
|
var favourite = Create();
|
|
favourite.Key = key;
|
|
favourite.Table = table;
|
|
favourite.AppUserId = appUserId;
|
|
favourite.Created = DateTimeOffset.UtcNow;
|
|
favourite.UpdatedAt = DateTimeOffset.UtcNow;
|
|
|
|
var created = await AddAsync(favourite, accessToken, token);
|
|
return created != null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Liste von Favoriten für eine Objektklasse für einen Benutzer zurück
|
|
/// </summary>
|
|
/// <param name="table">Gewünschtes Objekt</param>
|
|
/// <param name="location">Aktuelle Position</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <param name="appUserId">Id des AppUsers</param>
|
|
/// <returns>ListCommunicationResult</returns>
|
|
public async Task<CommunicationResult<List<FavouriteListItem>>> GetListAsync(string appUserId, string table, LocationDto location, string language, string accessToken, CancellationToken token)
|
|
{
|
|
var result = new CommunicationResult<List<FavouriteListItem>>() { Value = new List<FavouriteListItem>() };
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
if (isConnected)
|
|
{
|
|
var query = new FavouriteListQueryDto
|
|
{
|
|
Location =location,
|
|
Language = language,
|
|
AppUserId = appUserId,
|
|
Table = table
|
|
};
|
|
|
|
var queryResult = await _communicationService.GetFavouritesListAsync(query, accessToken, token);
|
|
if (queryResult.Success)
|
|
{
|
|
result.Success = true;
|
|
result.Value = queryResult.Value;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.Success = false;
|
|
result.ErrorCode = CommunicationErrors.ServerNoConnection;
|
|
result.ErrorMessage = Errors.Server_NoConnection;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#region Pull-Push Implementation
|
|
|
|
/// <summary>
|
|
/// Holen der letzten Daten vom Server und Synchronisieren mit den lokalen Daten
|
|
/// </summary>
|
|
/// <param name="language">Sprache</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Task</returns>
|
|
public async Task<SyncResult<Favourite>> PullAsync(string language, string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<Favourite>();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
|
|
if (isConnected)
|
|
{
|
|
var user = await _appUserRepository.FirstOrDefaultAsync(c => c.Id != "", false).ConfigureAwait(false);
|
|
|
|
//Zuerst lezte Aktivität holen...
|
|
DateTimeOffset? lastUpdate = null;
|
|
var lastSyncInfo = await _pullService.GetAsync(nameof(Favourite));
|
|
if (lastSyncInfo != null)
|
|
lastUpdate = lastSyncInfo.LastUpdate;
|
|
|
|
var requestResult = await _communicationService.GetFavouritesForSyncAsync(user.Id, lastUpdate, accessToken, token);
|
|
if (requestResult.Success)
|
|
{
|
|
result = await HandleChangesAsync(requestResult.Value);
|
|
if (result.LastUpdate != null)
|
|
await _pullService.AddOrUpddateAsync(nameof(Favourite), result.LastUpdate.Value).ConfigureAwait(false);
|
|
}
|
|
|
|
result.LastUpdate ??= lastUpdate;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Holen der Daten vom lokalen Speicher die noch nicht synchronisiert wurden und senden an den Server
|
|
/// </summary>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Task</returns>
|
|
public async Task<SyncResult<Favourite>> PushAsync(string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<Favourite>();
|
|
|
|
if (await _pushService.HasOpenAsync(nameof(Favourite)) > 0)
|
|
{
|
|
var deltas = await _pushService.GetAllAsync(nameof(Favourite));
|
|
if (deltas.Any())
|
|
{
|
|
var user = await _appUserRepository.FirstOrDefaultAsync(c => c.Id != "", false).ConfigureAwait(false);
|
|
deltas = deltas.OrderBy(c => c.DateTime).ToList();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
|
|
if (!isConnected) return result;
|
|
|
|
foreach (var syncInfoPush in deltas)
|
|
{
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(syncInfoPush.Value))
|
|
{
|
|
var request = JsonSerializer.Deserialize<Favourite>(syncInfoPush.Value, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
if (syncInfoPush.Operation == SyncOperation.Create)
|
|
{
|
|
var createDto = request.ToDto();
|
|
var createResult = await _communicationService.CreateFavouriteAsync(createDto, accessToken, token);
|
|
if (createResult.Success && createResult.Value.Status != CreateStatus.Error)
|
|
{
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
//TODO: Was tun wenn Fehler?
|
|
}
|
|
else if (syncInfoPush.Operation == SyncOperation.Edit)
|
|
{
|
|
var updateDto = request.ToDto();
|
|
var updateResult = await _communicationService.UpdateFavouriteAsync(updateDto, accessToken, token);
|
|
if (updateResult.Success && updateResult.Value)
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
//TODO: Was tun wenn Fehler?
|
|
}
|
|
else
|
|
{
|
|
var deleteDto = request.ToDto();
|
|
var deleteResult = await _communicationService.DeleteFavouriteAsync(deleteDto, user.Id, accessToken, token);
|
|
if (deleteResult.Success && deleteResult.Value)
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
//TODO: Was tun wenn Fehler?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
}
|
|
//Else ist nichts tun, konnte nicht übertragen werden.
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private
|
|
|
|
/// <summary>
|
|
/// Behandeln der Liste von Favoriten wenn welche vom Online-Store geholt werden.
|
|
/// </summary>
|
|
/// <param name="favourites">Liste der Favoriten</param>
|
|
/// <returns>Task</returns>
|
|
private async Task<SyncResult<Favourite>> HandleChangesAsync(List<Favourite> favourites)
|
|
{
|
|
var result = new SyncResult<Favourite>();
|
|
|
|
//Je Favorit durchgehen ob was gemacht werden soll
|
|
foreach (var favourite in favourites)
|
|
{
|
|
var localFavourite = await Repository.FirstOrDefaultAsync(c => c.Id == favourite.Id, false);
|
|
if (localFavourite != null && localFavourite.UpdatedAt < favourite.UpdatedAt)
|
|
{
|
|
if (localFavourite.UpdatedAt >= favourite.UpdatedAt)
|
|
{
|
|
if (result.LastUpdate == null || result.LastUpdate < localFavourite.UpdatedAt)
|
|
result.LastUpdate = localFavourite.UpdatedAt;
|
|
continue;
|
|
}
|
|
|
|
var deleted = localFavourite.Deleted == false && favourite.Deleted;
|
|
|
|
localFavourite.Version = favourite.Version;
|
|
localFavourite.UpdatedAt = favourite.UpdatedAt;
|
|
localFavourite.Deleted = favourite.Deleted;
|
|
|
|
localFavourite.AppUserId = favourite.AppUserId;
|
|
localFavourite.Key = favourite.Key;
|
|
localFavourite.Table = favourite.Table;
|
|
|
|
localFavourite.Created = favourite.Created;
|
|
|
|
if (result.LastUpdate == null || result.LastUpdate < localFavourite.UpdatedAt)
|
|
result.LastUpdate = localFavourite.UpdatedAt;
|
|
if (!deleted)
|
|
result.Updated.Add(localFavourite);
|
|
else
|
|
result.Deleted.Add(localFavourite);
|
|
Repository.Update(localFavourite);
|
|
}
|
|
|
|
if (localFavourite == null)
|
|
{
|
|
localFavourite = new Favourite()
|
|
{
|
|
Id = favourite.Id,
|
|
Version = favourite.Version,
|
|
UpdatedAt = favourite.UpdatedAt,
|
|
Deleted = favourite.Deleted,
|
|
|
|
AppUserId = favourite.AppUserId,
|
|
Key = favourite.Key,
|
|
Table = favourite.Table,
|
|
|
|
Created = favourite.Created
|
|
};
|
|
|
|
Repository.Add(localFavourite);
|
|
|
|
if (result.LastUpdate == null || result.LastUpdate < localFavourite.UpdatedAt)
|
|
result.LastUpdate = localFavourite.UpdatedAt;
|
|
result.Added.Add(localFavourite);
|
|
}
|
|
}
|
|
|
|
if (result.HasChanges)
|
|
{
|
|
try
|
|
{
|
|
await CommitAsync().ConfigureAwait(false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var err = ex.Message;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|