285 lines
12 KiB
C#
285 lines
12 KiB
C#
using System.Diagnostics;
|
|
using System.Reflection.Metadata;
|
|
using gehGassi.Dto;
|
|
using gehGassi.Dto.Common;
|
|
using gehGassi.Dto.News;
|
|
using gehGassiApp.Core.Data;
|
|
using gehGassiApp.Core.Interfaces;
|
|
using gehGassiApp.Core.Interfaces.Synchronization;
|
|
using gehGassiApp.Core.Resources;
|
|
using gehGassiApp.Domain.Common;
|
|
using gehGassiApp.Domain.News;
|
|
|
|
namespace gehGassiApp.Core.Services
|
|
{
|
|
/// <summary>
|
|
/// Service der alle Funktionen rund um News zur Verfügung stellt
|
|
/// </summary>
|
|
public class NewsService : ServiceBase<NewsCategory>, INewsService
|
|
{
|
|
private readonly ICommunicationService _communicationService;
|
|
private readonly ILocationService _locationService;
|
|
private readonly ISyncInfoPullService _syncInfoPullService;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="unitOfWork">Instanz eines IUnitOfWork</param>
|
|
/// <param name="communicationService">Instanz eines ICommunicationService</param>
|
|
/// <param name="locationService">Instanz eines ILocationService</param>
|
|
/// <param name="syncInfoPullService">Instanz eines ISyncInfoPullService</param>
|
|
public NewsService(IUnitOfWork unitOfWork, ICommunicationService communicationService, ILocationService locationService, ISyncInfoPullService syncInfoPullService) : base(unitOfWork)
|
|
{
|
|
_communicationService = communicationService;
|
|
_locationService = locationService;
|
|
_syncInfoPullService = syncInfoPullService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Liste der aktuellen News Kategorien zurück.
|
|
/// Entweder von der DB oder vom Server
|
|
/// </summary>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Liste der News Kategorien</returns>
|
|
public async Task<List<NewsCategory>> GetCategoriesAsync(string accessToken, string language, CancellationToken token)
|
|
{
|
|
//Zuerst DB
|
|
var localCategories = await Repository.FindAsync(c => c.Language == language && c.OnlineStatus == OnlineStatus.Online, noTracking: true).ConfigureAwait(false);
|
|
if (localCategories != null && localCategories.Any())
|
|
return localCategories.Where(c => c.OnlineStatus == OnlineStatus.Online && c.Deleted == false).OrderBy(c => c.Name).ToList();
|
|
else
|
|
{
|
|
//Dann wenn lokal nicht verfügbar immer online...
|
|
var isConnected = await _communicationService.IsConnected();
|
|
//isConnected = false;
|
|
if (isConnected)
|
|
{
|
|
var categoriesResult = await _communicationService.GetNewsCategoriesAsync(null, language, accessToken, token);
|
|
if (categoriesResult.Success)
|
|
{
|
|
var result = await HandleChangesAsync(categoriesResult.Value);
|
|
if (result.LastUpdate != null)
|
|
await _syncInfoPullService.AddOrUpddateAsync(nameof(NewsCategory), result.LastUpdate.Value).ConfigureAwait(false);
|
|
return categoriesResult.Value.Where(c => c.OnlineStatus == OnlineStatus.Online && c.Deleted == false).OrderBy(c => c.Name).ToList();
|
|
}
|
|
}
|
|
}
|
|
//Keine Daten online, keine offline
|
|
return new List<NewsCategory>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Abrufen von News. Berücksichtigt auch den Standort.
|
|
/// </summary>
|
|
/// <param name="categoryId">Id der Kategorie. Leer wenn ohne gewünscht</param>
|
|
/// <param name="location">Aktuelle Position</param>
|
|
/// <param name="take">Wie viele News sollen abgerufen werden?</param>
|
|
/// <param name="skip">Wie viele News sollen ausgelassen werden?</param>
|
|
/// <param name="appMode">Akteuller Modus der App</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Liste der News</returns>
|
|
public async Task<ListCommunicationResult<List<News>>> GetNewsAsync(string categoryId, LocationDto location, int take, int skip, AppMode appMode, string language, string accessToken, CancellationToken token)
|
|
{
|
|
var result = new ListCommunicationResult<List<News>>() { Value = new List<News>() };
|
|
|
|
var query = new NewsQueryDto
|
|
{
|
|
Location = location,
|
|
CategoryId = categoryId,
|
|
Language = language,
|
|
AppMode = (AppModeDto)appMode,
|
|
Take = take,
|
|
Skip = skip
|
|
};
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
if (isConnected)
|
|
{
|
|
var newsResult = await _communicationService.GetNewsAsync(query, accessToken, token);
|
|
if (newsResult.Success)
|
|
return newsResult;
|
|
}
|
|
else
|
|
{
|
|
result.Success = false;
|
|
result.ErrorCode = CommunicationErrors.ServerNoConnection;
|
|
result.ErrorMessage = Errors.Server_NoConnection;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Entität anhand der eindeutigen Id zurück
|
|
/// </summary>
|
|
/// <param name="id">Id der Entität</param>
|
|
/// <param name="noTracking">Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten</param>
|
|
/// <returns>Entität oder null, wenn nicht gefunden</returns>
|
|
public override NewsCategory Get(object id, bool noTracking = true)
|
|
{
|
|
return Repository.SingleOrDefault(c => c.Id == id.ToString(), noTracking);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Entität anhand der eindeutigen Id zurück
|
|
/// </summary>
|
|
/// <param name="id">Id der Entität</param>
|
|
/// <param name="noTracking">Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten</param>
|
|
/// <returns>Entität oder null, wenn nicht gefunden</returns>
|
|
public override async Task<NewsCategory> GetAsync(object id, bool noTracking = true)
|
|
{
|
|
return await Repository.SingleOrDefaultAsync(c => c.Id == id.ToString(), noTracking).ConfigureAwait(false);
|
|
}
|
|
|
|
#region Pull-Push Implementation
|
|
|
|
/// <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<NewsCategory>> PushAsync(string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<NewsCategory>();
|
|
|
|
//Es gibt hier kein Push!
|
|
await Task.Delay(1);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <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<NewsCategory>> PullAsync(string language, string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<NewsCategory>();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
|
|
if (isConnected)
|
|
{
|
|
//Zuerst lezte Aktivität holen...
|
|
DateTimeOffset? lastUpdate = null;
|
|
var lastSyncInfo = await _syncInfoPullService.GetAsync(nameof(NewsCategory));
|
|
if (lastSyncInfo != null)
|
|
lastUpdate = lastSyncInfo.LastUpdate;
|
|
|
|
var ctsQuery = new CancellationTokenSource(Common.Constants.PushPullTimeout);
|
|
var categoriesResult = await _communicationService.GetNewsCategoriesAsync(lastUpdate, language, accessToken, token);
|
|
if (categoriesResult.Success)
|
|
{
|
|
result = await HandleChangesAsync(categoriesResult.Value);
|
|
if(result.LastUpdate != null)
|
|
await _syncInfoPullService.AddOrUpddateAsync(nameof(NewsCategory), result.LastUpdate.Value).ConfigureAwait(false);
|
|
|
|
|
|
}
|
|
|
|
result.LastUpdate ??= lastUpdate;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private
|
|
|
|
/// <summary>
|
|
/// Behandeln der Liste von News-Kategorien wenn welche vom Online-Store geholt werden.
|
|
/// </summary>
|
|
/// <param name="categories">Liste der Kategorien</param>
|
|
/// <returns>Task</returns>
|
|
private async Task<SyncResult<NewsCategory>> HandleChangesAsync(List<NewsCategory> categories)
|
|
{
|
|
var result = new SyncResult<NewsCategory>();
|
|
|
|
//Je Kategorie durchgehen ob was gemacht werden soll
|
|
foreach (var newsCategory in categories)
|
|
{
|
|
var localCategory = await Repository.FirstOrDefaultAsync(c => c.Id == newsCategory.Id, false);
|
|
if (localCategory != null && localCategory.UpdatedAt < newsCategory.UpdatedAt)
|
|
{
|
|
if (localCategory.UpdatedAt >= newsCategory.UpdatedAt)
|
|
{
|
|
if (result.LastUpdate == null || result.LastUpdate < localCategory.UpdatedAt)
|
|
result.LastUpdate = localCategory.UpdatedAt;
|
|
continue;
|
|
}
|
|
var deleted = localCategory.Deleted == false && newsCategory.Deleted;
|
|
|
|
localCategory.Version = newsCategory.Version;
|
|
localCategory.UpdatedAt = newsCategory.UpdatedAt;
|
|
localCategory.Deleted = newsCategory.Deleted;
|
|
localCategory.Language = newsCategory.Language;
|
|
localCategory.Name = newsCategory.Name;
|
|
localCategory.Description = newsCategory.Description;
|
|
localCategory.Image = newsCategory.Image;
|
|
localCategory.ImageLanguage = newsCategory.ImageLanguage;
|
|
localCategory.OnlineStatus = newsCategory.OnlineStatus;
|
|
localCategory.Created = newsCategory.Created;
|
|
|
|
if(result.LastUpdate == null || result.LastUpdate < localCategory.UpdatedAt)
|
|
result.LastUpdate = localCategory.UpdatedAt;
|
|
if(!deleted)
|
|
result.Updated.Add(localCategory);
|
|
else
|
|
result.Deleted.Add(localCategory);
|
|
Repository.Update(localCategory);
|
|
}
|
|
|
|
if (localCategory == null)
|
|
{
|
|
localCategory = new NewsCategory
|
|
{
|
|
Id = newsCategory.Id,
|
|
Version = newsCategory.Version,
|
|
UpdatedAt = newsCategory.UpdatedAt,
|
|
Deleted = newsCategory.Deleted,
|
|
Language = newsCategory.Language,
|
|
Name = newsCategory.Name,
|
|
Description = newsCategory.Description,
|
|
Image = newsCategory.Image,
|
|
ImageLanguage = newsCategory.ImageLanguage,
|
|
OnlineStatus = newsCategory.OnlineStatus,
|
|
Created = newsCategory.Created
|
|
};
|
|
|
|
Repository.Add(localCategory);
|
|
|
|
if (result.LastUpdate == null || result.LastUpdate < localCategory.UpdatedAt)
|
|
result.LastUpdate = localCategory.UpdatedAt;
|
|
result.Added.Add(localCategory);
|
|
}
|
|
}
|
|
|
|
if (result.HasChanges)
|
|
{
|
|
try
|
|
{
|
|
await CommitAsync().ConfigureAwait(false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var err = ex.Message;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|