Files

360 lines
13 KiB
C#

using FoodsharingSiegen.Contracts;
using FoodsharingSiegen.Contracts.Entity;
using FoodsharingSiegen.Contracts.Enums;
using FoodsharingSiegen.Contracts.Model;
using FoodsharingSiegen.Server.Auth;
using Microsoft.EntityFrameworkCore;
namespace FoodsharingSiegen.Server.Data.Service
{
/// <summary>
/// The prospect service class (a. beging, 01.04.2022)
/// </summary>
/// <seealso cref="ServiceBase"/>
public class ProspectService : ServiceBase
{
private AuditService AuditService { get; }
#region Setup/Teardown
/// <summary>
/// Initializes a new instance of the <see cref="ProspectService"/> class
/// </summary>
/// <param name="context">The context</param>
/// <param name="authService"></param>
/// <param name="auditService"></param>
public ProspectService(FsContext context, AuthService authService, AuditService auditService) : base(context, authService) => AuditService = auditService;
#endregion
#region Public Method AddInteraction
/// <summary>
/// Adds the interaction using the specified interaction (a. beging, 02.04.2022)
/// </summary>
/// <param name="interaction">The interaction</param>
/// <returns>A task containing an operation result of interaction</returns>
public async Task<OperationResult<Interaction>> AddInteraction(Interaction interaction)
{
try
{
var targetProspect = await Context.Prospects!.Include(x => x.Interactions).FirstOrDefaultAsync(x => x.Id == interaction.ProspectID);
if (targetProspect == null) return new(new Exception("Invalid prospect id"));
interaction.ProspectID = Guid.Empty;
interaction.Created = DateTime.UtcNow;
targetProspect.Interactions.Add(interaction);
targetProspect.Modified = DateTime.UtcNow;
await Context.SaveChangesAsync();
await AuditService.Insert(AuditType.AddInteraction, targetProspect.Name, interaction.Type.ToString());
// Detatch entities
Context.Entry(targetProspect).State = EntityState.Detached;
Context.Entry(interaction).State = EntityState.Detached;
return new(interaction);
}
catch (Exception e)
{
return new(e);
}
}
#endregion
#region Public Method AddProspectAsync
/// <summary>
/// Adds the prospect using the specified prospect (a. beging, 01.04.2022)
/// </summary>
/// <param name="prospect">The prospect</param>
/// <returns>A task containing an operation result of prospect</returns>
public async Task<OperationResult<Prospect>> AddProspectAsync(Prospect? prospect)
{
try
{
if (prospect == null) return new(new Exception("Cannot be empty"));
prospect.Created = DateTime.UtcNow;
prospect.Modified = DateTime.UtcNow;
prospect.Id = Guid.Empty;
await Context.Prospects!.AddAsync(prospect);
var saveR = await Context.SaveChangesAsync();
if (saveR > 0)
{
await AuditService.Insert(AuditType.CreateProspect, prospect.Name, prospect.FsId.ToString());
return new(prospect);
}
return new(new Exception("Couldn't add prospect"));
}
catch (Exception e)
{
return new(e);
}
}
#endregion
#region Public Method GetProspectsAsync
/// <summary>
/// Gets the users (a. beging, 01.04.2022)
/// </summary>
/// <returns>A task containing an operation result of list prospect</returns>
public async Task<OperationResult<List<Prospect>>> GetProspectsAsync(GetProspectsParameter parameter)
{
try
{
var prospectsQuery = Context.Prospects!.AsNoTracking()
.Include(x => x.Images)
.Include(x => x.Interactions.OrderBy(i => i.Date)).ThenInclude(x => x.User)
.OrderBy(x => x.Name).AsQueryable();
if(parameter.MustHaveInteractions != null && parameter.MustHaveInteractions.Any())
prospectsQuery = prospectsQuery.Where(x => x.Interactions.Any(i => parameter.MustHaveInteractions.Contains(i.Type)));
if(parameter.CannotHaveInteractions != null && parameter.CannotHaveInteractions.Any())
prospectsQuery = prospectsQuery.Where(x => x.Interactions.All(i => !parameter.CannotHaveInteractions.Contains(i.Type)));
if (!parameter.IncludeDeleted)
prospectsQuery = prospectsQuery.Where(x => x.RecordState != RecordState.Archived);
var prospects = await prospectsQuery.ToListAsync();
return new(prospects);
}
catch (Exception e)
{
return new(e);
}
}
#endregion
#region Public Method RemoveInteraction
/// <summary>
/// Removes the interaction using the specified interaction id (a. beging, 11.04.2022)
/// </summary>
/// <param name="interactionId">The interaction id</param>
/// <returns>A task containing the operation result</returns>
public async Task<OperationResult> RemoveInteraction(Guid interactionId)
{
try
{
var interaction = await Context.Interactions!.AsNoTracking().FirstOrDefaultAsync(x => x.Id == interactionId);
if(interaction == null) return new(new Exception("Interaction not found"));
Context.Interactions!.Remove(new() { Id = interaction.Id });
await Context.SaveChangesAsync();
// Update prospect modified date
var prospect = await Context.Prospects!.FirstOrDefaultAsync(x => x.Id == interaction.ProspectID);
if (prospect != null)
{
prospect.Modified = DateTime.UtcNow;
await Context.SaveChangesAsync();
}
await AuditService.Insert(AuditType.RemoveInteraction, "?");
return new();
}
catch (Exception e)
{
return new(e);
}
}
#endregion
#region Public Method UpdateAsync
/// <summary>
/// Updates the prospect (a. beging, 11.04.2022)
/// </summary>
/// <param name="prospect">The prospect</param>
/// <returns>A task containing the operation result</returns>
public async Task<OperationResult> UpdateAsync(Prospect prospect)
{
try
{
var entityProspect = await Context.Prospects!.FirstOrDefaultAsync(x => x.Id == prospect.Id);
if (entityProspect == null) return new(new Exception("Prospect not found"));
entityProspect.Memo = prospect.Memo;
entityProspect.Name = prospect.Name;
entityProspect.FsId = prospect.FsId;
entityProspect.Warning = prospect.Warning;
entityProspect.RecordState = prospect.RecordState;
entityProspect.Modified = DateTime.UtcNow;
var saveR = await Context.SaveChangesAsync();
if(saveR < 1) return new(new Exception("Fehler beim speichern"));
await AuditService.Insert(AuditType.EditProspect, prospect.Name);
return new();
}
catch (Exception e)
{
return new(e);
}
}
#endregion
#region Image Upload Features
public async Task<OperationResult<Guid>> GenerateVerificationTokenAsync(Guid prospectId)
{
try
{
var prospect = await Context.Prospects!
.Include(x => x.Interactions)
.FirstOrDefaultAsync(x => x.Id == prospectId);
if (prospect == null) return new(new Exception("Prospect not found"));
if (prospect.Interactions.Any(x => x.Type == InteractionType.Verify))
return new(new Exception("Die Identitätsprüfung wurde bereits abgeschlossen. Es kann kein neuer Token generiert werden."));
prospect.VerificationToken = Guid.NewGuid();
prospect.Modified = DateTime.UtcNow;
await Context.SaveChangesAsync();
return new(prospect.VerificationToken.Value);
}
catch (Exception e)
{
return new(e);
}
}
public async Task<OperationResult<Prospect>> GetProspectByVerificationTokenAsync(Guid token)
{
try
{
var prospect = await Context.Prospects!
.Include(x => x.Interactions)
.Include(x => x.Images)
.AsNoTracking()
.FirstOrDefaultAsync(x => x.VerificationToken == token);
if (prospect == null) return new(new Exception("Ungültiger oder abgelaufener Token."));
if (prospect.Interactions.Any(x => x.Type == InteractionType.Verify))
return new(new Exception("Die Identitätsprüfung wurde bereits abgeschlossen. Ein Hochladen weiterer Bilder ist nicht mehr möglich."));
return new(prospect);
}
catch (Exception e)
{
return new(e);
}
}
public async Task<OperationResult> AddVerificationImageAsync(Guid prospectId, byte[] imageData, string contentType)
{
try
{
var prospect = await Context.Prospects!
.Include(x => x.Interactions)
.AsNoTracking()
.FirstOrDefaultAsync(x => x.Id == prospectId);
if (prospect == null) return new(new Exception("Foodsaver nicht gefunden."));
if (prospect.Interactions.Any(x => x.Type == InteractionType.Verify))
return new(new Exception("Die Identitätsprüfung wurde bereits abgeschlossen. Ein Hochladen weiterer Bilder ist nicht mehr möglich."));
// Verify max 5 images
var imgCount = await Context.ProspectImages!.CountAsync(x => x.ProspectId == prospectId);
if (imgCount >= 5) return new(new Exception("Maximum 5 images allowed"));
var image = new ProspectImage
{
Id = Guid.NewGuid(),
ProspectId = prospectId,
ImageData = imageData,
ContentType = contentType,
Created = DateTime.UtcNow
};
await Context.ProspectImages!.AddAsync(image);
await Context.SaveChangesAsync();
await AuditService.Insert(AuditType.UploadProspectImage, prospect.Name);
return new();
}
catch (Exception e)
{
return new(e);
}
}
public async Task<OperationResult<List<ProspectImage>>> GetVerificationImagesAsync(Guid prospectId)
{
try
{
var images = await Context.ProspectImages!
.AsNoTracking()
.Where(x => x.ProspectId == prospectId)
.OrderBy(x => x.Created)
.ToListAsync();
var prospectName = await Context.Prospects!
.Where(x => x.Id == prospectId)
.Select(x => x.Name)
.FirstOrDefaultAsync();
if (!string.IsNullOrEmpty(prospectName))
{
await AuditService.Insert(AuditType.ViewProspectImages, prospectName);
}
return new(images);
}
catch (Exception e)
{
return new(e);
}
}
public async Task<OperationResult> DeleteVerificationImagesAsync(Guid prospectId)
{
try
{
var images = await Context.ProspectImages!.Where(x => x.ProspectId == prospectId).ToListAsync();
if (images.Any())
{
Context.ProspectImages!.RemoveRange(images);
var prospect = await Context.Prospects!.FirstOrDefaultAsync(x => x.Id == prospectId);
if (prospect != null)
{
prospect.VerificationToken = null; // Clear token when images are deleted
await AuditService.Insert(AuditType.DeleteProspectImages, prospect.Name);
}
await Context.SaveChangesAsync();
}
return new();
}
catch (Exception e)
{
return new(e);
}
}
#endregion
}
}